From a78cc041843dbb198f15482263ff5f4b96ad7da4 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Fri, 28 Jun 2024 17:12:15 -0600 Subject: [PATCH 01/54] ci: replace macos-11 with macos-12 (#618) --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4f93f2c2..2ba9b375 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-11] + os: [ubuntu-latest, macos-12] toolchain: [stable, nightly] steps: From 36bcc5dbe9095e5e75c59db51d75f5776c39f8fc Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Fri, 28 Jun 2024 17:28:57 -0600 Subject: [PATCH 02/54] feat: signer interactivity (#617) Makes signer implementations specify whether a signing operation is "interactive" (or just expensive). Utilizing this new information, `Account` and `AccountFactory` now make more informed decisions on whether to request real signatures for different types of operations. The most significant benefit of this change is allowing using hardware wallet without excessive unnecessary signing requests. --- README.md | 6 +- examples/declare_cairo0_contract.rs | 3 +- examples/declare_cairo1_contract.rs | 3 +- examples/deploy_account_with_ledger.rs | 1 + examples/deploy_argent_account.rs | 1 + examples/mint_tokens.rs | 2 +- examples/transfer_with_ledger.rs | 57 ++++++++ starknet-accounts/src/account/declaration.rs | 133 +++++++++++++----- starknet-accounts/src/account/execution.rs | 86 ++++++++--- starknet-accounts/src/account/mod.rs | 20 +++ starknet-accounts/src/factory/argent.rs | 4 + starknet-accounts/src/factory/mod.rs | 90 +++++++++--- .../src/factory/open_zeppelin.rs | 4 + starknet-accounts/src/single_owner.rs | 4 + starknet-signers/src/ledger.rs | 4 + starknet-signers/src/local_wallet.rs | 4 + starknet-signers/src/signer.rs | 10 ++ 17 files changed, 347 insertions(+), 85 deletions(-) create mode 100644 examples/transfer_with_ledger.rs diff --git a/README.md b/README.md index d5639993..99b88ea6 100644 --- a/README.md +++ b/README.md @@ -100,9 +100,11 @@ Examples can be found in the [examples folder](./examples): 10. [Deploy an OpenZeppelin account with Ledger](./examples/deploy_account_with_ledger.rs) -11. [Parsing a JSON-RPC request on the server side](./examples/parse_jsonrpc_request.rs) +11. [Transfer ERC20 tokens with Ledger](./examples/transfer_with_ledger.rs) -12. [Inspecting a erased provider-specific error type](./examples/downcast_provider_error.rs) +12. [Parsing a JSON-RPC request on the server side](./examples/parse_jsonrpc_request.rs) + +13. [Inspecting a erased provider-specific error type](./examples/downcast_provider_error.rs) ## License diff --git a/examples/declare_cairo0_contract.rs b/examples/declare_cairo0_contract.rs index bb7dadfc..1bf94b0d 100644 --- a/examples/declare_cairo0_contract.rs +++ b/examples/declare_cairo0_contract.rs @@ -45,5 +45,6 @@ async fn main() { .await .unwrap(); - dbg!(result); + println!("Transaction hash: {:#064x}", result.transaction_hash); + println!("Class hash: {:#064x}", result.class_hash); } diff --git a/examples/declare_cairo1_contract.rs b/examples/declare_cairo1_contract.rs index f6f2fb3d..86ab0fdd 100644 --- a/examples/declare_cairo1_contract.rs +++ b/examples/declare_cairo1_contract.rs @@ -53,5 +53,6 @@ async fn main() { .await .unwrap(); - dbg!(result); + println!("Transaction hash: {:#064x}", result.transaction_hash); + println!("Class hash: {:#064x}", result.class_hash); } diff --git a/examples/deploy_account_with_ledger.rs b/examples/deploy_account_with_ledger.rs index 0f25ad2b..ef4ba9ae 100644 --- a/examples/deploy_account_with_ledger.rs +++ b/examples/deploy_account_with_ledger.rs @@ -51,6 +51,7 @@ async fn main() { match result { Ok(tx) => { println!("Transaction hash: {:#064x}", tx.transaction_hash); + println!("Account: {:#064x}", tx.contract_address); } Err(err) => { eprintln!("Error: {err}"); diff --git a/examples/deploy_argent_account.rs b/examples/deploy_argent_account.rs index 8eff33cc..acd559c7 100644 --- a/examples/deploy_argent_account.rs +++ b/examples/deploy_argent_account.rs @@ -47,6 +47,7 @@ async fn main() { match result { Ok(tx) => { println!("Transaction hash: {:#064x}", tx.transaction_hash); + println!("Account: {:#064x}", tx.contract_address); } Err(err) => { eprintln!("Error: {err}"); diff --git a/examples/mint_tokens.rs b/examples/mint_tokens.rs index 33e86ea2..64fc7ada 100644 --- a/examples/mint_tokens.rs +++ b/examples/mint_tokens.rs @@ -51,5 +51,5 @@ async fn main() { .await .unwrap(); - dbg!(result); + println!("Transaction hash: {:#064x}", result.transaction_hash); } diff --git a/examples/transfer_with_ledger.rs b/examples/transfer_with_ledger.rs new file mode 100644 index 00000000..223da492 --- /dev/null +++ b/examples/transfer_with_ledger.rs @@ -0,0 +1,57 @@ +use starknet::{ + accounts::{Account, Call, ExecutionEncoding, SingleOwnerAccount}, + core::{ + chain_id, + types::{BlockId, BlockTag, Felt}, + utils::get_selector_from_name, + }, + macros::felt, + providers::{ + jsonrpc::{HttpTransport, JsonRpcClient}, + Url, + }, + signers::LedgerSigner, +}; + +#[tokio::main] +async fn main() { + let provider = JsonRpcClient::new(HttpTransport::new( + Url::parse("https://starknet-sepolia.public.blastapi.io/rpc/v0_7").unwrap(), + )); + + let signer = LedgerSigner::new( + "m/2645'/1195502025'/1470455285'/0'/0'/0" + .try_into() + .expect("unable to parse path"), + ) + .await + .expect("failed to initialize Starknet Ledger app"); + let address = Felt::from_hex("YOUR_ACCOUNT_CONTRACT_ADDRESS_IN_HEX_HERE").unwrap(); + let eth_token_address = + Felt::from_hex("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7") + .unwrap(); + + let mut account = SingleOwnerAccount::new( + provider, + signer, + address, + chain_id::SEPOLIA, + ExecutionEncoding::New, + ); + + // `SingleOwnerAccount` defaults to checking nonce and estimating fees against the latest + // block. Optionally change the target block to pending with the following line: + account.set_block_id(BlockId::Tag(BlockTag::Pending)); + + let result = account + .execute_v1(vec![Call { + to: eth_token_address, + selector: get_selector_from_name("transfer").unwrap(), + calldata: vec![felt!("0x1234"), felt!("100"), Felt::ZERO], + }]) + .send() + .await + .unwrap(); + + println!("Transaction hash: {:#064x}", result.transaction_hash); +} diff --git a/starknet-accounts/src/account/declaration.rs b/starknet-accounts/src/account/declaration.rs index 5162320f..360dc924 100644 --- a/starknet-accounts/src/account/declaration.rs +++ b/starknet-accounts/src/account/declaration.rs @@ -12,6 +12,7 @@ use starknet_core::{ BroadcastedDeclareTransactionV2, BroadcastedDeclareTransactionV3, BroadcastedTransaction, DataAvailabilityMode, DeclareTransactionResult, FeeEstimate, Felt, FlattenedSierraClass, ResourceBounds, ResourceBoundsMapping, SimulatedTransaction, SimulationFlag, + SimulationFlagForEstimateFee, }, }; use starknet_crypto::PoseidonHasher; @@ -195,6 +196,8 @@ where &self, nonce: Felt, ) -> Result> { + let skip_signature = self.account.is_signer_interactive(); + let prepared = PreparedDeclarationV2 { account: self.account, inner: RawDeclarationV2 { @@ -204,13 +207,19 @@ where max_fee: Felt::ZERO, }, }; - let declare = prepared.get_declare_request(true).await?; + let declare = prepared.get_declare_request(true, skip_signature).await?; self.account .provider() .estimate_fee_single( BroadcastedTransaction::Declare(BroadcastedDeclareTransaction::V2(declare)), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.account.block_id(), ) .await @@ -223,6 +232,16 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.account.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedDeclarationV2 { account: self.account, inner: RawDeclarationV2 { @@ -232,7 +251,7 @@ where max_fee: self.max_fee.unwrap_or_default(), }, }; - let declare = prepared.get_declare_request(true).await?; + let declare = prepared.get_declare_request(true, skip_signature).await?; let mut flags = vec![]; @@ -470,6 +489,8 @@ where &self, nonce: Felt, ) -> Result> { + let skip_signature = self.account.is_signer_interactive(); + let prepared = PreparedDeclarationV3 { account: self.account, inner: RawDeclarationV3 { @@ -480,13 +501,19 @@ where gas_price: 0, }, }; - let declare = prepared.get_declare_request(true).await?; + let declare = prepared.get_declare_request(true, skip_signature).await?; self.account .provider() .estimate_fee_single( BroadcastedTransaction::Declare(BroadcastedDeclareTransaction::V3(declare)), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.account.block_id(), ) .await @@ -499,6 +526,16 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.account.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedDeclarationV3 { account: self.account, inner: RawDeclarationV3 { @@ -509,7 +546,7 @@ where gas_price: self.gas_price.unwrap_or_default(), }, }; - let declare = prepared.get_declare_request(true).await?; + let declare = prepared.get_declare_request(true, skip_signature).await?; let mut flags = vec![]; @@ -673,6 +710,8 @@ where &self, nonce: Felt, ) -> Result> { + let skip_signature = self.account.is_signer_interactive(); + let prepared = PreparedLegacyDeclaration { account: self.account, inner: RawLegacyDeclaration { @@ -681,13 +720,19 @@ where max_fee: Felt::ZERO, }, }; - let declare = prepared.get_declare_request(true).await?; + let declare = prepared.get_declare_request(true, skip_signature).await?; self.account .provider() .estimate_fee_single( BroadcastedTransaction::Declare(BroadcastedDeclareTransaction::V1(declare)), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.account.block_id(), ) .await @@ -700,6 +745,16 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.account.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedLegacyDeclaration { account: self.account, inner: RawLegacyDeclaration { @@ -708,7 +763,7 @@ where max_fee: self.max_fee.unwrap_or_default(), }, }; - let declare = prepared.get_declare_request(true).await?; + let declare = prepared.get_declare_request(true, skip_signature).await?; let mut flags = vec![]; @@ -895,7 +950,7 @@ where A: ConnectedAccount, { pub async fn send(&self) -> Result> { - let tx_request = self.get_declare_request(false).await?; + let tx_request = self.get_declare_request(false, false).await?; self.account .provider() .add_declare_transaction(BroadcastedDeclareTransaction::V2(tx_request)) @@ -903,19 +958,21 @@ where .map_err(AccountError::Provider) } - pub async fn get_declare_request( + async fn get_declare_request( &self, query_only: bool, + skip_signature: bool, ) -> Result> { - let signature = self - .account - .sign_declaration_v2(&self.inner, query_only) - .await - .map_err(AccountError::Signing)?; - Ok(BroadcastedDeclareTransactionV2 { max_fee: self.inner.max_fee, - signature, + signature: if skip_signature { + vec![] + } else { + self.account + .sign_declaration_v2(&self.inner, query_only) + .await + .map_err(AccountError::Signing)? + }, nonce: self.inner.nonce, contract_class: self.inner.contract_class.clone(), compiled_class_hash: self.inner.compiled_class_hash, @@ -942,7 +999,7 @@ where A: ConnectedAccount, { pub async fn send(&self) -> Result> { - let tx_request = self.get_declare_request(false).await?; + let tx_request = self.get_declare_request(false, false).await?; self.account .provider() .add_declare_transaction(BroadcastedDeclareTransaction::V3(tx_request)) @@ -950,20 +1007,22 @@ where .map_err(AccountError::Provider) } - pub async fn get_declare_request( + async fn get_declare_request( &self, query_only: bool, + skip_signature: bool, ) -> Result> { - let signature = self - .account - .sign_declaration_v3(&self.inner, query_only) - .await - .map_err(AccountError::Signing)?; - Ok(BroadcastedDeclareTransactionV3 { sender_address: self.account.address(), compiled_class_hash: self.inner.compiled_class_hash, - signature, + signature: if skip_signature { + vec![] + } else { + self.account + .sign_declaration_v3(&self.inner, query_only) + .await + .map_err(AccountError::Signing)? + }, nonce: self.inner.nonce, contract_class: self.inner.contract_class.clone(), resource_bounds: ResourceBoundsMapping { @@ -1008,7 +1067,7 @@ where A: ConnectedAccount, { pub async fn send(&self) -> Result> { - let tx_request = self.get_declare_request(false).await?; + let tx_request = self.get_declare_request(false, false).await?; self.account .provider() .add_declare_transaction(BroadcastedDeclareTransaction::V1(tx_request)) @@ -1016,21 +1075,23 @@ where .map_err(AccountError::Provider) } - pub async fn get_declare_request( + async fn get_declare_request( &self, query_only: bool, + skip_signature: bool, ) -> Result> { - let signature = self - .account - .sign_legacy_declaration(&self.inner, query_only) - .await - .map_err(AccountError::Signing)?; - let compressed_class = self.inner.contract_class.compress().unwrap(); Ok(BroadcastedDeclareTransactionV1 { max_fee: self.inner.max_fee, - signature, + signature: if skip_signature { + vec![] + } else { + self.account + .sign_legacy_declaration(&self.inner, query_only) + .await + .map_err(AccountError::Signing)? + }, nonce: self.inner.nonce, contract_class: Arc::new(compressed_class), sender_address: self.account.address(), diff --git a/starknet-accounts/src/account/execution.rs b/starknet-accounts/src/account/execution.rs index cef482fc..99757da0 100644 --- a/starknet-accounts/src/account/execution.rs +++ b/starknet-accounts/src/account/execution.rs @@ -10,7 +10,7 @@ use starknet_core::{ BroadcastedInvokeTransaction, BroadcastedInvokeTransactionV1, BroadcastedInvokeTransactionV3, BroadcastedTransaction, DataAvailabilityMode, FeeEstimate, Felt, InvokeTransactionResult, ResourceBounds, ResourceBoundsMapping, SimulatedTransaction, - SimulationFlag, + SimulationFlag, SimulationFlagForEstimateFee, }, }; use starknet_crypto::PoseidonHasher; @@ -245,6 +245,8 @@ where &self, nonce: Felt, ) -> Result> { + let skip_signature = self.account.is_signer_interactive(); + let prepared = PreparedExecutionV1 { account: self.account, inner: RawExecutionV1 { @@ -254,7 +256,7 @@ where }, }; let invoke = prepared - .get_invoke_request(true) + .get_invoke_request(true, skip_signature) .await .map_err(AccountError::Signing)?; @@ -262,7 +264,13 @@ where .provider() .estimate_fee_single( BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(invoke)), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.account.block_id(), ) .await @@ -275,6 +283,16 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.account.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedExecutionV1 { account: self.account, inner: RawExecutionV1 { @@ -284,7 +302,7 @@ where }, }; let invoke = prepared - .get_invoke_request(true) + .get_invoke_request(true, skip_signature) .await .map_err(AccountError::Signing)?; @@ -450,6 +468,8 @@ where &self, nonce: Felt, ) -> Result> { + let skip_signature = self.account.is_signer_interactive(); + let prepared = PreparedExecutionV3 { account: self.account, inner: RawExecutionV3 { @@ -460,7 +480,7 @@ where }, }; let invoke = prepared - .get_invoke_request(true) + .get_invoke_request(true, skip_signature) .await .map_err(AccountError::Signing)?; @@ -468,7 +488,13 @@ where .provider() .estimate_fee_single( BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V3(invoke)), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.account.block_id(), ) .await @@ -481,6 +507,16 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.account.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedExecutionV3 { account: self.account, inner: RawExecutionV3 { @@ -491,7 +527,7 @@ where }, }; let invoke = prepared - .get_invoke_request(true) + .get_invoke_request(true, skip_signature) .await .map_err(AccountError::Signing)?; @@ -682,7 +718,7 @@ where { pub async fn send(&self) -> Result> { let tx_request = self - .get_invoke_request(false) + .get_invoke_request(false, false) .await .map_err(AccountError::Signing)?; self.account @@ -695,18 +731,20 @@ where // The `simulate` function is temporarily removed until it's supported in [Provider] // TODO: add `simulate` back once transaction simulation in supported - pub async fn get_invoke_request( + async fn get_invoke_request( &self, query_only: bool, + skip_signature: bool, ) -> Result { - let signature = self - .account - .sign_execution_v1(&self.inner, query_only) - .await?; - Ok(BroadcastedInvokeTransactionV1 { max_fee: self.inner.max_fee, - signature, + signature: if skip_signature { + vec![] + } else { + self.account + .sign_execution_v1(&self.inner, query_only) + .await? + }, nonce: self.inner.nonce, sender_address: self.account.address(), calldata: self.account.encode_calls(&self.inner.calls), @@ -721,7 +759,7 @@ where { pub async fn send(&self) -> Result> { let tx_request = self - .get_invoke_request(false) + .get_invoke_request(false, false) .await .map_err(AccountError::Signing)?; self.account @@ -734,19 +772,21 @@ where // The `simulate` function is temporarily removed until it's supported in [Provider] // TODO: add `simulate` back once transaction simulation in supported - pub async fn get_invoke_request( + async fn get_invoke_request( &self, query_only: bool, + skip_signature: bool, ) -> Result { - let signature = self - .account - .sign_execution_v3(&self.inner, query_only) - .await?; - Ok(BroadcastedInvokeTransactionV3 { sender_address: self.account.address(), calldata: self.account.encode_calls(&self.inner.calls), - signature, + signature: if skip_signature { + vec![] + } else { + self.account + .sign_execution_v3(&self.inner, query_only) + .await? + }, nonce: self.inner.nonce, resource_bounds: ResourceBoundsMapping { l1_gas: ResourceBounds { diff --git a/starknet-accounts/src/account/mod.rs b/starknet-accounts/src/account/mod.rs index 30e39730..f2e6d62e 100644 --- a/starknet-accounts/src/account/mod.rs +++ b/starknet-accounts/src/account/mod.rs @@ -55,6 +55,14 @@ pub trait Account: ExecutionEncoder + Sized { query_only: bool, ) -> Result, Self::SignError>; + /// Whether the underlying signer implementation is interactive, such as a hardware wallet. + /// Implementations should return `true` if the signing operation is very expensive, even if not + /// strictly "interactive" as in requiring human input. + /// + /// This affects how an account makes decision on whether to request a real signature for + /// estimation/simulation purposes. + fn is_signer_interactive(&self) -> bool; + fn execute_v1(&self, calls: Vec) -> ExecutionV1 { ExecutionV1::new(calls, self) } @@ -354,6 +362,10 @@ where .sign_legacy_declaration(legacy_declaration, query_only) .await } + + fn is_signer_interactive(&self) -> bool { + (*self).is_signer_interactive() + } } #[cfg_attr(not(target_arch = "wasm32"), async_trait)] @@ -417,6 +429,10 @@ where .sign_legacy_declaration(legacy_declaration, query_only) .await } + + fn is_signer_interactive(&self) -> bool { + self.as_ref().is_signer_interactive() + } } #[cfg_attr(not(target_arch = "wasm32"), async_trait)] @@ -480,6 +496,10 @@ where .sign_legacy_declaration(legacy_declaration, query_only) .await } + + fn is_signer_interactive(&self) -> bool { + self.as_ref().is_signer_interactive() + } } #[cfg_attr(not(target_arch = "wasm32"), async_trait)] diff --git a/starknet-accounts/src/factory/argent.rs b/starknet-accounts/src/factory/argent.rs index bed65a97..5bfa0476 100644 --- a/starknet-accounts/src/factory/argent.rs +++ b/starknet-accounts/src/factory/argent.rs @@ -73,6 +73,10 @@ where &self.provider } + fn is_signer_interactive(&self) -> bool { + self.signer.is_interactive() + } + fn block_id(&self) -> BlockId { self.block_id } diff --git a/starknet-accounts/src/factory/mod.rs b/starknet-accounts/src/factory/mod.rs index aef251a4..1dc3b773 100644 --- a/starknet-accounts/src/factory/mod.rs +++ b/starknet-accounts/src/factory/mod.rs @@ -8,7 +8,7 @@ use starknet_core::{ BroadcastedDeployAccountTransactionV1, BroadcastedDeployAccountTransactionV3, BroadcastedTransaction, DataAvailabilityMode, DeployAccountTransactionResult, FeeEstimate, Felt, NonZeroFelt, ResourceBounds, ResourceBoundsMapping, SimulatedTransaction, - SimulationFlag, StarknetError, + SimulationFlag, SimulationFlagForEstimateFee, StarknetError, }, }; use starknet_crypto::PoseidonHasher; @@ -73,6 +73,14 @@ pub trait AccountFactory: Sized { fn provider(&self) -> &Self::Provider; + /// Whether the underlying signer implementation is interactive, such as a hardware wallet. + /// Implementations should return `true` if the signing operation is very expensive, even if not + /// strictly "interactive" as in requiring human input. + /// + /// This affects how an account factory makes decision on whether to request a real signature + /// for estimation/simulation purposes. + fn is_signer_interactive(&self) -> bool; + /// Block ID to use when estimating fees. fn block_id(&self) -> BlockId { BlockId::Tag(BlockTag::Latest) @@ -413,6 +421,8 @@ where &self, nonce: Felt, ) -> Result> { + let skip_signature = self.factory.is_signer_interactive(); + let prepared = PreparedAccountDeploymentV1 { factory: self.factory, inner: RawAccountDeploymentV1 { @@ -422,7 +432,7 @@ where }, }; let deploy = prepared - .get_deploy_request(true) + .get_deploy_request(true, skip_signature) .await .map_err(AccountFactoryError::Signing)?; @@ -432,7 +442,13 @@ where BroadcastedTransaction::DeployAccount(BroadcastedDeployAccountTransaction::V1( deploy, )), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.factory.block_id(), ) .await @@ -445,6 +461,16 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.factory.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedAccountDeploymentV1 { factory: self.factory, inner: RawAccountDeploymentV1 { @@ -454,7 +480,7 @@ where }, }; let deploy = prepared - .get_deploy_request(true) + .get_deploy_request(true, skip_signature) .await .map_err(AccountFactoryError::Signing)?; @@ -645,6 +671,8 @@ where &self, nonce: Felt, ) -> Result> { + let skip_signature = self.factory.is_signer_interactive(); + let prepared = PreparedAccountDeploymentV3 { factory: self.factory, inner: RawAccountDeploymentV3 { @@ -655,7 +683,7 @@ where }, }; let deploy = prepared - .get_deploy_request(true) + .get_deploy_request(true, skip_signature) .await .map_err(AccountFactoryError::Signing)?; @@ -665,7 +693,13 @@ where BroadcastedTransaction::DeployAccount(BroadcastedDeployAccountTransaction::V3( deploy, )), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.factory.block_id(), ) .await @@ -678,6 +712,16 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.factory.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedAccountDeploymentV3 { factory: self.factory, inner: RawAccountDeploymentV3 { @@ -688,7 +732,7 @@ where }, }; let deploy = prepared - .get_deploy_request(true) + .get_deploy_request(true, skip_signature) .await .map_err(AccountFactoryError::Signing)?; @@ -802,7 +846,7 @@ where &self, ) -> Result> { let tx_request = self - .get_deploy_request(false) + .get_deploy_request(false, false) .await .map_err(AccountFactoryError::Signing)?; self.factory @@ -815,15 +859,17 @@ where async fn get_deploy_request( &self, query_only: bool, + skip_signature: bool, ) -> Result { - let signature = self - .factory - .sign_deployment_v1(&self.inner, query_only) - .await?; - Ok(BroadcastedDeployAccountTransactionV1 { max_fee: self.inner.max_fee, - signature, + signature: if skip_signature { + vec![] + } else { + self.factory + .sign_deployment_v1(&self.inner, query_only) + .await? + }, nonce: self.inner.nonce, contract_address_salt: self.inner.salt, constructor_calldata: self.factory.calldata(), @@ -911,7 +957,7 @@ where &self, ) -> Result> { let tx_request = self - .get_deploy_request(false) + .get_deploy_request(false, false) .await .map_err(AccountFactoryError::Signing)?; self.factory @@ -924,14 +970,16 @@ where async fn get_deploy_request( &self, query_only: bool, + skip_signature: bool, ) -> Result { - let signature = self - .factory - .sign_deployment_v3(&self.inner, query_only) - .await?; - Ok(BroadcastedDeployAccountTransactionV3 { - signature, + signature: if skip_signature { + vec![] + } else { + self.factory + .sign_deployment_v3(&self.inner, query_only) + .await? + }, nonce: self.inner.nonce, contract_address_salt: self.inner.salt, constructor_calldata: self.factory.calldata(), diff --git a/starknet-accounts/src/factory/open_zeppelin.rs b/starknet-accounts/src/factory/open_zeppelin.rs index 72882e45..3b23b16e 100644 --- a/starknet-accounts/src/factory/open_zeppelin.rs +++ b/starknet-accounts/src/factory/open_zeppelin.rs @@ -70,6 +70,10 @@ where &self.provider } + fn is_signer_interactive(&self) -> bool { + self.signer.is_interactive() + } + fn block_id(&self) -> BlockId { self.block_id } diff --git a/starknet-accounts/src/single_owner.rs b/starknet-accounts/src/single_owner.rs index 9aa7a5b7..0677a8d8 100644 --- a/starknet-accounts/src/single_owner.rs +++ b/starknet-accounts/src/single_owner.rs @@ -170,6 +170,10 @@ where Ok(vec![signature.r, signature.s]) } + + fn is_signer_interactive(&self) -> bool { + self.signer.is_interactive() + } } impl ExecutionEncoder for SingleOwnerAccount diff --git a/starknet-signers/src/ledger.rs b/starknet-signers/src/ledger.rs index 140d787c..8071a78f 100644 --- a/starknet-signers/src/ledger.rs +++ b/starknet-signers/src/ledger.rs @@ -163,6 +163,10 @@ impl Signer for LedgerSigner { Ok(signature) } + + fn is_interactive(&self) -> bool { + true + } } impl From for LedgerError { diff --git a/starknet-signers/src/local_wallet.rs b/starknet-signers/src/local_wallet.rs index 23c00b28..2c898da0 100644 --- a/starknet-signers/src/local_wallet.rs +++ b/starknet-signers/src/local_wallet.rs @@ -36,6 +36,10 @@ impl Signer for LocalWallet { async fn sign_hash(&self, hash: &Felt) -> Result { Ok(self.private_key.sign(hash)?) } + + fn is_interactive(&self) -> bool { + false + } } impl From for LocalWallet { diff --git a/starknet-signers/src/signer.rs b/starknet-signers/src/signer.rs index 0f586f82..429efede 100644 --- a/starknet-signers/src/signer.rs +++ b/starknet-signers/src/signer.rs @@ -15,4 +15,14 @@ pub trait Signer { async fn get_public_key(&self) -> Result; async fn sign_hash(&self, hash: &Felt) -> Result; + + /// Whether the underlying signer implementation is interactive, such as a hardware wallet. + /// Implementations should return `true` if the signing operation is very expensive, even if not + /// strictly "interactive" as in requiring human input. + /// + /// This mainly affects the transaction simulation strategy used by higher-level types. With + /// non-interactive signers, it's fine to sign multiple times for getting the most accurate + /// estimation/simulation possible; but with interactive signers, they would accept less + /// accurate results to minimize signing requests. + fn is_interactive(&self) -> bool; } From 1ea9e7207d31b36f4e77d23868f2ea12b5393ea6 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Fri, 28 Jun 2024 20:50:29 -0600 Subject: [PATCH 03/54] fix: `std` not enabled for `starknet-types-core` (#619) --- Cargo.lock | 17 +++++++++++++++++ starknet-crypto/Cargo.toml | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 2ab904b9..1e814960 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1116,11 +1116,27 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "lambdaworks-crypto" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb5d4f22241504f7c7b8d2c3a7d7835d7c07117f10bff2a7d96a9ef6ef217c3" +dependencies = [ + "lambdaworks-math", + "serde", + "sha2", + "sha3", +] + [[package]] name = "lambdaworks-math" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "358e172628e713b80a530a59654154bfc45783a6ed70ea284839800cebdf8f97" +dependencies = [ + "serde", + "serde_json", +] [[package]] name = "lazy_static" @@ -2112,6 +2128,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe29a53d28ff630e4c7827788f14b28f9386d27cb9d05186a5f2e73218c34677" dependencies = [ + "lambdaworks-crypto", "lambdaworks-math", "num-bigint", "num-integer", diff --git a/starknet-crypto/Cargo.toml b/starknet-crypto/Cargo.toml index c81cd10b..75b185d2 100644 --- a/starknet-crypto/Cargo.toml +++ b/starknet-crypto/Cargo.toml @@ -29,7 +29,7 @@ starknet-types-core = { version = "0.1.3", default-features = false, features = [features] default = ["std", "signature-display"] -std = [] +std = ["starknet-types-core/std"] alloc = ["hex?/alloc", "starknet-types-core/alloc"] signature-display = ["dep:hex", "alloc"] From 838c612e445ae22af07beceaba862c708da2ab2d Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Fri, 28 Jun 2024 21:29:00 -0600 Subject: [PATCH 04/54] release: bump starknet-crypto to 0.7.1 (#620) --- Cargo.lock | 2 +- Cargo.toml | 2 +- examples/starknet-wasm/Cargo.toml | 2 +- starknet-accounts/Cargo.toml | 2 +- starknet-core/Cargo.toml | 2 +- starknet-crypto/Cargo.toml | 2 +- starknet-signers/Cargo.toml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e814960..a46c8dd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2028,7 +2028,7 @@ dependencies = [ [[package]] name = "starknet-crypto" -version = "0.7.0" +version = "0.7.1" dependencies = [ "criterion", "crypto-bigint", diff --git a/Cargo.toml b/Cargo.toml index 1d9542a6..b3c0f9cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ members = [ all-features = true [dependencies] -starknet-crypto = { version = "0.7.0", path = "./starknet-crypto" } +starknet-crypto = { version = "0.7.1", path = "./starknet-crypto" } starknet-core = { version = "0.11.1", path = "./starknet-core", default-features = false } starknet-providers = { version = "0.11.0", path = "./starknet-providers" } starknet-contract = { version = "0.10.0", path = "./starknet-contract" } diff --git a/examples/starknet-wasm/Cargo.toml b/examples/starknet-wasm/Cargo.toml index cf4f900c..2ec65513 100644 --- a/examples/starknet-wasm/Cargo.toml +++ b/examples/starknet-wasm/Cargo.toml @@ -19,6 +19,6 @@ crate-type = ["cdylib", "rlib"] default = ["console_error_panic_hook"] [dependencies] -starknet-crypto = { version = "0.7.0", path = "../../starknet-crypto" } +starknet-crypto = { version = "0.7.1", path = "../../starknet-crypto" } console_error_panic_hook = { version = "0.1.7", optional = true } wasm-bindgen = "0.2.84" diff --git a/starknet-accounts/Cargo.toml b/starknet-accounts/Cargo.toml index 55827140..6ad3ad82 100644 --- a/starknet-accounts/Cargo.toml +++ b/starknet-accounts/Cargo.toml @@ -15,7 +15,7 @@ exclude = ["test-data/**"] [dependencies] starknet-core = { version = "0.11.1", path = "../starknet-core" } -starknet-crypto = { version = "0.7.0", path = "../starknet-crypto" } +starknet-crypto = { version = "0.7.1", path = "../starknet-crypto" } starknet-providers = { version = "0.11.0", path = "../starknet-providers" } starknet-signers = { version = "0.9.0", path = "../starknet-signers" } async-trait = "0.1.68" diff --git a/starknet-core/Cargo.toml b/starknet-core/Cargo.toml index 5be48640..cc501344 100644 --- a/starknet-core/Cargo.toml +++ b/starknet-core/Cargo.toml @@ -17,7 +17,7 @@ exclude = ["test-data/**"] all-features = true [dependencies] -starknet-crypto = { version = "0.7.0", path = "../starknet-crypto", default-features = false, features = ["alloc"] } +starknet-crypto = { version = "0.7.1", path = "../starknet-crypto", default-features = false, features = ["alloc"] } base64 = { version = "0.21.0", default-features = false, features = ["alloc"] } crypto-bigint = { version = "0.5.1", default-features = false } flate2 = { version = "1.0.25", optional = true } diff --git a/starknet-crypto/Cargo.toml b/starknet-crypto/Cargo.toml index 75b185d2..2c73c00f 100644 --- a/starknet-crypto/Cargo.toml +++ b/starknet-crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-crypto" -version = "0.7.0" +version = "0.7.1" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" diff --git a/starknet-signers/Cargo.toml b/starknet-signers/Cargo.toml index 75467e7c..9a378f45 100644 --- a/starknet-signers/Cargo.toml +++ b/starknet-signers/Cargo.toml @@ -14,7 +14,7 @@ keywords = ["ethereum", "starknet", "web3"] [dependencies] starknet-core = { version = "0.11.1", path = "../starknet-core" } -starknet-crypto = { version = "0.7.0", path = "../starknet-crypto" } +starknet-crypto = { version = "0.7.1", path = "../starknet-crypto" } async-trait = "0.1.68" auto_impl = "1.0.1" thiserror = "1.0.40" From 702008d296907765162e6cadecb5b9f8acf83995 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Sat, 29 Jun 2024 02:21:14 -0600 Subject: [PATCH 05/54] feat: add `LedgerStarknetApp` type for Ledger specific operations (#621) --- starknet-signers/src/ledger.rs | 91 +++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 12 deletions(-) diff --git a/starknet-signers/src/ledger.rs b/starknet-signers/src/ledger.rs index 8071a78f..5bffac18 100644 --- a/starknet-signers/src/ledger.rs +++ b/starknet-signers/src/ledger.rs @@ -22,12 +22,19 @@ const EIP_2645_PATH_LENGTH: usize = 6; const PUBLIC_KEY_SIZE: usize = 65; const SIGNATURE_SIZE: usize = 65; +/// Ledger app wrapper that implements the [`Signer`] trait. #[derive(Debug)] pub struct LedgerSigner { - transport: Ledger, + app: LedgerStarknetApp, derivation_path: DerivationPath, } +/// A handle for communicating with the Ledger Starknet app. +#[derive(Debug)] +pub struct LedgerStarknetApp { + transport: Ledger, +} + #[derive(Debug, thiserror::Error)] pub enum LedgerError { #[error("derivation path is empty, not prefixed with m/2645', or is not 6-level long")] @@ -77,8 +84,6 @@ impl LedgerSigner { /// /// Currently, the Ledger app only enforces the length and the first level of the path. pub async fn new(derivation_path: DerivationPath) -> Result { - let transport = Ledger::init().await?; - if !matches!(derivation_path.iter().next(), Some(&EIP_2645_PURPOSE)) || derivation_path.len() != EIP_2645_PATH_LENGTH { @@ -86,7 +91,7 @@ impl LedgerSigner { } Ok(Self { - transport, + app: LedgerStarknetApp::new().await?, derivation_path, }) } @@ -98,12 +103,57 @@ impl Signer for LedgerSigner { type SignError = LedgerError; async fn get_public_key(&self) -> Result { + self.app + .get_public_key(self.derivation_path.clone(), false) + .await + } + + async fn sign_hash(&self, hash: &Felt) -> Result { + self.app.sign_hash(self.derivation_path.clone(), hash).await + } + + fn is_interactive(&self) -> bool { + true + } +} + +impl LedgerStarknetApp { + /// Initializes the Starknet Ledger app. Attempts to find and connect to a Ledger device. The + /// device must be unlocked and have the Starknet app open. + pub async fn new() -> Result { + let transport = Ledger::init().await?; + + Ok(Self { transport }) + } + + /// Gets a public key from the app for a particular derivation path, with optional on-device + /// confirmation for extra security. + /// + /// The derivation path _must_ follow EIP-2645, i.e. having `2645'` as its "purpose" level as + /// per BIP-44, as the Ledger app does not allow other paths to be used. + /// + /// The path _must_ also be 6-level in length. An example path for Starknet would be: + /// + /// `m/2645'/1195502025'/1470455285'/0'/0'/0` + /// + /// where: + /// + /// - `2645'` is the EIP-2645 prefix + /// - `1195502025'`, decimal for `0x4741e9c9`, is the 31 lowest bits for `sha256(starknet)` + /// - `1470455285'`, decimal for `0x57a55df5`, is the 31 lowest bits for `sha256(starkli)` + /// + /// Currently, the Ledger app only enforces the length and the first level of the path. + async fn get_public_key( + &self, + derivation_path: DerivationPath, + display: bool, + ) -> Result { let response = self .transport .exchange( &GetPubKeyCommand { - display: false, - path: self.derivation_path.clone(), + display, + path: derivation_path, } .into(), ) @@ -123,13 +173,34 @@ impl Signer for LedgerSigner { Ok(VerifyingKey::from_scalar(pubkey_x)) } - async fn sign_hash(&self, hash: &Felt) -> Result { + /// Requests a signature for a **raw hash** with a certain derivation path. Currently the Ledger + /// app only supports blind signing raw hashes. + /// + /// The derivation path _must_ follow EIP-2645, i.e. having `2645'` as its "purpose" level as + /// per BIP-44, as the Ledger app does not allow other paths to be used. + /// + /// The path _must_ also be 6-level in length. An example path for Starknet would be: + /// + /// `m/2645'/1195502025'/1470455285'/0'/0'/0` + /// + /// where: + /// + /// - `2645'` is the EIP-2645 prefix + /// - `1195502025'`, decimal for `0x4741e9c9`, is the 31 lowest bits for `sha256(starknet)` + /// - `1470455285'`, decimal for `0x57a55df5`, is the 31 lowest bits for `sha256(starkli)` + /// + /// Currently, the Ledger app only enforces the length and the first level of the path. + async fn sign_hash( + &self, + derivation_path: DerivationPath, + hash: &Felt, + ) -> Result { get_apdu_data( &self .transport .exchange( &SignHashCommand1 { - path: self.derivation_path.clone(), + path: derivation_path, } .into(), ) @@ -163,10 +234,6 @@ impl Signer for LedgerSigner { Ok(signature) } - - fn is_interactive(&self) -> bool { - true - } } impl From for LedgerError { From 50eed828021365f86d346953ea017587f452aa9e Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Sat, 29 Jun 2024 02:38:07 -0600 Subject: [PATCH 06/54] fix: `LedgerStarknetApp` method privacy (#622) --- starknet-signers/src/ledger.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/starknet-signers/src/ledger.rs b/starknet-signers/src/ledger.rs index 5bffac18..beca1775 100644 --- a/starknet-signers/src/ledger.rs +++ b/starknet-signers/src/ledger.rs @@ -143,7 +143,7 @@ impl LedgerStarknetApp { /// - `1470455285'`, decimal for `0x57a55df5`, is the 31 lowest bits for `sha256(starkli)` /// /// Currently, the Ledger app only enforces the length and the first level of the path. - async fn get_public_key( + pub async fn get_public_key( &self, derivation_path: DerivationPath, display: bool, @@ -190,7 +190,7 @@ impl LedgerStarknetApp { /// - `1470455285'`, decimal for `0x57a55df5`, is the 31 lowest bits for `sha256(starkli)` /// /// Currently, the Ledger app only enforces the length and the first level of the path. - async fn sign_hash( + pub async fn sign_hash( &self, derivation_path: DerivationPath, hash: &Felt, From db1fa598232f0698d942cc974f481b5d888ac080 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Sat, 29 Jun 2024 15:42:04 -0600 Subject: [PATCH 07/54] feat: get ledger app version (#623) --- Cargo.lock | 7 +++++++ starknet-signers/Cargo.toml | 3 ++- starknet-signers/src/ledger.rs | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index a46c8dd0..aa130718 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1782,6 +1782,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.203" @@ -2116,6 +2122,7 @@ dependencies = [ "eth-keystore", "getrandom", "rand", + "semver", "starknet-core", "starknet-crypto", "thiserror", diff --git a/starknet-signers/Cargo.toml b/starknet-signers/Cargo.toml index 9a378f45..d0515adf 100644 --- a/starknet-signers/Cargo.toml +++ b/starknet-signers/Cargo.toml @@ -21,6 +21,7 @@ thiserror = "1.0.40" crypto-bigint = { version = "0.5.1", default-features = false } rand = { version = "0.8.5", features = ["std_rng"] } coins-bip32 = { version = "0.11.1", optional = true } +semver = { version = "1.0.23", optional = true } # Using a fork until https://github.com/summa-tx/coins/issues/137 is fixed coins-ledger = { git = "https://github.com/xJonathanLEI/coins", rev = "0e3be5db0b18b683433de6b666556b99c726e785", default-features = false, optional = true } @@ -37,4 +38,4 @@ wasm-bindgen-test = "0.3.34" [features] default = [] -ledger = ["coins-bip32", "coins-ledger"] +ledger = ["coins-bip32", "coins-ledger", "semver"] diff --git a/starknet-signers/src/ledger.rs b/starknet-signers/src/ledger.rs index beca1775..e86ae90d 100644 --- a/starknet-signers/src/ledger.rs +++ b/starknet-signers/src/ledger.rs @@ -5,6 +5,7 @@ use coins_ledger::{ APDUAnswer, APDUCommand, Ledger, }; use crypto_bigint::{ArrayEncoding, U256}; +use semver::Version; use starknet_core::{crypto::Signature, types::Felt}; use crate::{Signer, VerifyingKey}; @@ -19,6 +20,7 @@ const EIP_2645_PURPOSE: u32 = 0x80000a55; const EIP_2645_PATH_LENGTH: usize = 6; +const VERSION_SIZE: usize = 3; const PUBLIC_KEY_SIZE: usize = 65; const SIGNATURE_SIZE: usize = 65; @@ -49,6 +51,9 @@ pub enum LedgerError { UnexpectedResponseLength { expected: usize, actual: usize }, } +/// The `GetPubKey` Ledger command. +struct GetVersion; + /// The `GetPubKey` Ledger command. struct GetPubKeyCommand { display: bool, @@ -126,6 +131,21 @@ impl LedgerStarknetApp { Ok(Self { transport }) } + /// Gets the Ledger app version. + pub async fn get_version(&self) -> Result { + let response = self.transport.exchange(&GetVersion.into()).await?; + + let data = get_apdu_data(&response)?; + if data.len() != VERSION_SIZE { + return Err(LedgerError::UnexpectedResponseLength { + expected: VERSION_SIZE, + actual: data.len(), + }); + } + + Ok(Version::new(data[0] as u64, data[1] as u64, data[2] as u64)) + } + /// Gets a public key from the app for a particular derivation path, with optional on-device /// confirmation for extra security. /// @@ -242,6 +262,19 @@ impl From for LedgerError { } } +impl From for APDUCommand { + fn from(_value: GetVersion) -> Self { + Self { + cla: CLA_STARKNET, + ins: 0x00, + p1: 0x00, + p2: 0x00, + data: APDUData::new(&[]), + response_len: None, + } + } +} + impl From for APDUCommand { fn from(value: GetPubKeyCommand) -> Self { let path = value From b28241c0036cabb2cece8206c6c0b94908a286ff Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Thu, 4 Jul 2024 23:14:56 +0800 Subject: [PATCH 08/54] re-export starknet-types-core felt module (#616) --- starknet-core/src/types/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starknet-core/src/types/mod.rs b/starknet-core/src/types/mod.rs index e5494a82..16614753 100644 --- a/starknet-core/src/types/mod.rs +++ b/starknet-core/src/types/mod.rs @@ -5,7 +5,7 @@ use serde_with::serde_as; use crate::serde::unsigned_field_element::UfeHex; -pub use starknet_types_core::felt::{Felt, NonZeroFelt}; +pub use starknet_types_core::felt::*; mod conversions; From 7bb13d3f02f23949cf3c263e1b53ffcc43990ce6 Mon Sep 17 00:00:00 2001 From: Guspan Tanadi <36249910+guspan-tanadi@users.noreply.github.com> Date: Thu, 4 Jul 2024 22:19:01 +0700 Subject: [PATCH 09/54] docs(README): link version IAccount.cairo (#624) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 99b88ea6..ba8e58a1 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ starknet = { git = "https://github.com/xJonathanLEI/starknet-rs" } - [x] Sequencer gateway / feeder gateway client - [x] Full node JSON-RPC API client - [x] Smart contract deployment -- [x] Signer for using [IAccount](https://github.com/OpenZeppelin/cairo-contracts/blob/main/src/openzeppelin/account/IAccount.cairo) account contracts +- [x] Signer for using [IAccount](https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/src/openzeppelin/account/IAccount.cairo) account contracts - [ ] Strongly-typed smart contract binding code generation from ABI - [x] Ledger hardware wallet support From ee149a4584dfc797b81398ebf6afcd3fee7f3b36 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Sun, 14 Jul 2024 15:51:32 -0600 Subject: [PATCH 10/54] chore: make clippy happy again (#627) --- starknet-providers/src/sequencer/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/starknet-providers/src/sequencer/mod.rs b/starknet-providers/src/sequencer/mod.rs index 8e83a11e..74d05225 100644 --- a/starknet-providers/src/sequencer/mod.rs +++ b/starknet-providers/src/sequencer/mod.rs @@ -174,9 +174,6 @@ enum RawFieldElementResponse { SequencerError(SequencerError), } -#[derive(Deserialize)] -struct EmptyObject {} - impl SequencerGatewayProvider { fn extend_gateway_url(&self, segment: &str) -> Url { let mut url = self.gateway_url.clone(); From fc9b9209e714bcd4b5f439ec32bdc720112f684d Mon Sep 17 00:00:00 2001 From: TheVeloper Date: Mon, 15 Jul 2024 00:04:23 +0200 Subject: [PATCH 11/54] refactor: replace Pedersen implementation with type-rs (#614) --- starknet-crypto/Cargo.toml | 2 +- starknet-crypto/src/pedersen_hash.rs | 45 ++++------------------------ 2 files changed, 6 insertions(+), 41 deletions(-) diff --git a/starknet-crypto/Cargo.toml b/starknet-crypto/Cargo.toml index 2c73c00f..07312853 100644 --- a/starknet-crypto/Cargo.toml +++ b/starknet-crypto/Cargo.toml @@ -25,7 +25,7 @@ rfc6979 = { version = "0.4.0", default-features = false } sha2 = { version = "0.10.6", default-features = false } zeroize = { version = "1.6.0", default-features = false } hex = { version = "0.4.3", default-features = false, optional = true } -starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve"] } +starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve", "hash"] } [features] default = ["std", "signature-display"] diff --git a/starknet-crypto/src/pedersen_hash.rs b/starknet-crypto/src/pedersen_hash.rs index a5026750..a59c5345 100644 --- a/starknet-crypto/src/pedersen_hash.rs +++ b/starknet-crypto/src/pedersen_hash.rs @@ -1,8 +1,7 @@ -use starknet_curve::curve_params; -use starknet_types_core::curve::{AffinePoint, ProjectivePoint}; -use starknet_types_core::felt::Felt; - -use crate::pedersen_points::*; +use starknet_types_core::{ + felt::Felt, + hash::{Pedersen, StarkHash}, +}; /// Computes the Starkware version of the Pedersen hash of x and y. All inputs are little-endian. /// @@ -11,41 +10,7 @@ use crate::pedersen_points::*; /// * `x`: The x coordinate /// * `y`: The y coordinate pub fn pedersen_hash(x: &Felt, y: &Felt) -> Felt { - let x = x.to_bits_le(); - let y = y.to_bits_le(); - - // Preprocessed material is lookup-tables for each chunk of bits - let table_size = (1 << CURVE_CONSTS_BITS) - 1; - let add_points = |acc: &mut ProjectivePoint, bits: &[bool], prep: &[AffinePoint]| { - bits.chunks(CURVE_CONSTS_BITS) - .enumerate() - .for_each(|(i, v)| { - let offset = v - .iter() - .rev() - .fold(0, |acc, &bit| (acc << 1) + bit as usize); - if offset > 0 { - // Table lookup at 'offset-1' in table for chunk 'i' - *acc += &prep[i * table_size + offset - 1]; - } - }); - }; - - // Compute hash - let mut acc = - ProjectivePoint::from_affine(curve_params::SHIFT_POINT.x(), curve_params::SHIFT_POINT.y()) - .unwrap(); - - add_points(&mut acc, &x[..248], &CURVE_CONSTS_P0); // Add a_low * P1 - add_points(&mut acc, &x[248..252], &CURVE_CONSTS_P1); // Add a_high * P2 - add_points(&mut acc, &y[..248], &CURVE_CONSTS_P2); // Add b_low * P3 - add_points(&mut acc, &y[248..252], &CURVE_CONSTS_P3); // Add b_high * P4 - - // Convert to affine - let result = acc.to_affine().unwrap(); - - // Return x-coordinate - result.x() + Pedersen::hash(x, y) } #[cfg(test)] From c943cd876960fc2a2382c991d006f7c8b8df6fc0 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 15 Jul 2024 15:55:20 +0200 Subject: [PATCH 12/54] Replace declare_v1 suggestion with declare_v2 (#628) --- starknet-accounts/src/account/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starknet-accounts/src/account/mod.rs b/starknet-accounts/src/account/mod.rs index f2e6d62e..94c9031c 100644 --- a/starknet-accounts/src/account/mod.rs +++ b/starknet-accounts/src/account/mod.rs @@ -92,7 +92,7 @@ pub trait Account: ExecutionEncoder + Sized { DeclarationV3::new(contract_class, compiled_class_hash, self) } - #[deprecated = "use version specific variants (`declare_v1` & `declare_v3`) instead"] + #[deprecated = "use version specific variants (`declare_v2` & `declare_v3`) instead"] fn declare( &self, contract_class: Arc, From 6a9f124bf9d973f27360e72bb486576beb7b53a2 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Mon, 15 Jul 2024 21:55:39 +0800 Subject: [PATCH 13/54] include `starknet-types-core` std (#615) --- starknet-core/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starknet-core/Cargo.toml b/starknet-core/Cargo.toml index cc501344..7f189a68 100644 --- a/starknet-core/Cargo.toml +++ b/starknet-core/Cargo.toml @@ -39,7 +39,7 @@ wasm-bindgen-test = "0.3.34" [features] default = ["std"] -std = ["dep:flate2", "starknet-crypto/std"] +std = ["dep:flate2", "starknet-crypto/std", "starknet-types-core/std"] no_unknown_fields = [] [[bench]] From 08a7807072c3b327de72eacc467bb7fa4324b346 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Tue, 16 Jul 2024 01:19:38 +0200 Subject: [PATCH 14/54] chore: bump `serde_with` to 3.9 (#625) This is a breaking change as `serde_with` ends up in the public API. --- Cargo.lock | 113 ++++++++++++++++++++++++---------- starknet-contract/Cargo.toml | 2 +- starknet-core/Cargo.toml | 2 +- starknet-providers/Cargo.toml | 2 +- 4 files changed, 85 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa130718..4d5b040b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,15 +112,15 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.13.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "base64" -version = "0.21.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -277,7 +277,7 @@ checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "bitflags 1.3.2", "clap_lex", - "indexmap", + "indexmap 1.9.3", "textwrap", ] @@ -527,9 +527,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.14.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -537,27 +537,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.14.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 1.0.109", + "syn 2.0.63", ] [[package]] name = "darling_macro" -version = "0.14.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 1.0.109", + "syn 2.0.63", ] [[package]] @@ -570,6 +570,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "digest" version = "0.10.7" @@ -630,6 +640,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "eth-keystore" version = "0.5.0" @@ -824,7 +840,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -843,6 +859,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1050,7 +1072,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", "serde", ] @@ -1267,6 +1300,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.45" @@ -1416,6 +1455,12 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1844,15 +1889,17 @@ dependencies = [ [[package]] name = "serde_with" -version = "2.3.2" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331bb8c3bf9b92457ab7abecf07078c13f7d270ba490103e84e8b014490cd0b0" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" dependencies = [ - "base64 0.13.1", + "base64 0.22.1", "chrono", "hex", - "indexmap", + "indexmap 1.9.3", + "indexmap 2.2.6", "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -1860,14 +1907,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "2.3.2" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859011bddcc11f289f07f467cc1fe01c7a941daa4d8f6c40d4d1c92eb6d9319c" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ "darling", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.63", ] [[package]] @@ -2160,9 +2207,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" @@ -2235,11 +2282,14 @@ dependencies = [ [[package]] name = "time" -version = "0.3.20" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ + "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -2247,16 +2297,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.8" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -2361,7 +2412,7 @@ version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" dependencies = [ - "indexmap", + "indexmap 1.9.3", "toml_datetime", "winnow", ] diff --git a/starknet-contract/Cargo.toml b/starknet-contract/Cargo.toml index 290e3e55..1c44ac28 100644 --- a/starknet-contract/Cargo.toml +++ b/starknet-contract/Cargo.toml @@ -19,7 +19,7 @@ starknet-providers = { version = "0.11.0", path = "../starknet-providers" } starknet-accounts = { version = "0.10.0", path = "../starknet-accounts" } serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0.96" -serde_with = "2.3.2" +serde_with = "3.9.0" thiserror = "1.0.40" [dev-dependencies] diff --git a/starknet-core/Cargo.toml b/starknet-core/Cargo.toml index 7f189a68..a9215c23 100644 --- a/starknet-core/Cargo.toml +++ b/starknet-core/Cargo.toml @@ -25,7 +25,7 @@ hex = { version = "0.4.3", default-features = false, features = ["alloc"] } serde = { version = "1.0.160", default-features = false, features = ["derive"] } serde_json = { version = "1.0.96", default-features = false, features = ["alloc", "raw_value"] } serde_json_pythonic = { version = "0.1.2", default-features = false, features = ["alloc", "raw_value"] } -serde_with = { version = "2.3.2", default-features = false, features = ["alloc", "macros"] } +serde_with = { version = "3.9.0", default-features = false, features = ["alloc", "macros"] } sha3 = { version = "0.10.7", default-features = false } starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve", "serde", "num-traits"] } diff --git a/starknet-providers/Cargo.toml b/starknet-providers/Cargo.toml index 3760028c..48db0b55 100644 --- a/starknet-providers/Cargo.toml +++ b/starknet-providers/Cargo.toml @@ -25,7 +25,7 @@ reqwest = { version = "0.11.16", default-features = false, features = ["rustls-t thiserror = "1.0.40" serde = "1.0.160" serde_json = "1.0.96" -serde_with = "2.3.2" +serde_with = "3.9.0" [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2.9", features = ["js"] } From b8a0003997b9c2adad4620285916bc75a3e98fbc Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Tue, 16 Jul 2024 12:11:03 +0800 Subject: [PATCH 15/54] feat: de/serialize based on human readability (#532) Co-authored-by: Jonathan LEI --- Cargo.lock | 10 + starknet-core/Cargo.toml | 1 + starknet-core/src/serde/num_hex.rs | 46 ++++- .../src/serde/unsigned_field_element.rs | 184 ++++++++++++++++-- starknet-core/src/types/hash_256.rs | 50 ++++- 5 files changed, 268 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d5b040b..913a3aa3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,6 +134,15 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -2063,6 +2072,7 @@ name = "starknet-core" version = "0.11.1" dependencies = [ "base64 0.21.0", + "bincode", "criterion", "crypto-bigint", "flate2", diff --git a/starknet-core/Cargo.toml b/starknet-core/Cargo.toml index a9215c23..a035ded2 100644 --- a/starknet-core/Cargo.toml +++ b/starknet-core/Cargo.toml @@ -30,6 +30,7 @@ sha3 = { version = "0.10.7", default-features = false } starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve", "serde", "num-traits"] } [dev-dependencies] +bincode = "1.3.3" criterion = { version = "0.4.0", default-features = false } hex-literal = "0.4.1" starknet-core = { path = ".", features = ["no_unknown_fields"] } diff --git a/starknet-core/src/serde/num_hex.rs b/starknet-core/src/serde/num_hex.rs index 985b9053..6268fb1e 100644 --- a/starknet-core/src/serde/num_hex.rs +++ b/starknet-core/src/serde/num_hex.rs @@ -9,21 +9,29 @@ pub mod u64 { where S: Serializer, { - serializer.serialize_str(&format!("{value:#x}")) + if serializer.is_human_readable() { + serializer.serialize_str(&format!("{value:#x}")) + } else { + serializer.serialize_u64(*value) + } } pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { - deserializer.deserialize_any(NumHexVisitor) + if deserializer.is_human_readable() { + deserializer.deserialize_str(NumHexVisitor) + } else { + deserializer.deserialize_u64(NumHexVisitor) + } } impl<'de> Visitor<'de> for NumHexVisitor { type Value = u64; fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { - write!(formatter, "string") + write!(formatter, "string, or an array of u8") } fn visit_str(self, v: &str) -> Result @@ -33,5 +41,37 @@ pub mod u64 { u64::from_str_radix(v.trim_start_matches("0x"), 16) .map_err(|err| serde::de::Error::custom(format!("invalid u64 hex string: {err}"))) } + + fn visit_u64(self, v: u64) -> Result + where + E: serde::de::Error, + { + Ok(v) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use hex_literal::hex; + use serde::{Deserialize, Serialize}; + + #[derive(Serialize, Deserialize)] + struct TestStruct(#[serde(with = "u64")] pub u64); + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_ser() { + let r = bincode::serialize(&TestStruct(0x1234)).unwrap(); + assert_eq!(r, hex!("3412000000000000")); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_deser() { + let r = bincode::deserialize::(&hex!("3412000000000000")).unwrap(); + assert_eq!(r.0, 0x1234); } } diff --git a/starknet-core/src/serde/unsigned_field_element.rs b/starknet-core/src/serde/unsigned_field_element.rs index 38317ff9..f443797a 100644 --- a/starknet-core/src/serde/unsigned_field_element.rs +++ b/starknet-core/src/serde/unsigned_field_element.rs @@ -1,5 +1,6 @@ use alloc::{fmt::Formatter, format}; +use crypto_bigint::U256; use serde::{ de::{Error as DeError, Visitor}, Deserializer, Serializer, @@ -8,6 +9,9 @@ use serde_with::{DeserializeAs, SerializeAs}; use starknet_types_core::felt::Felt; +const PRIME: U256 = + U256::from_be_hex("0800000000000011000000000000000000000000000000000000000000000001"); + pub struct UfeHex; pub struct UfeHexOption; @@ -23,7 +27,11 @@ impl SerializeAs for UfeHex { where S: Serializer, { - serializer.serialize_str(&format!("{value:#x}")) + if serializer.is_human_readable() { + serializer.serialize_str(&format!("{value:#x}")) + } else { + serializer.serialize_bytes(&value.to_bytes_be()) + } } } @@ -32,7 +40,11 @@ impl<'de> DeserializeAs<'de, Felt> for UfeHex { where D: Deserializer<'de>, { - deserializer.deserialize_any(UfeHexVisitor) + if deserializer.is_human_readable() { + deserializer.deserialize_any(UfeHexVisitor) + } else { + deserializer.deserialize_bytes(UfeHexVisitor) + } } } @@ -40,7 +52,7 @@ impl<'de> Visitor<'de> for UfeHexVisitor { type Value = Felt; fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { - write!(formatter, "string") + write!(formatter, "a hex string, or an array of u8") } fn visit_str(self, v: &str) -> Result @@ -49,6 +61,16 @@ impl<'de> Visitor<'de> for UfeHexVisitor { { Felt::from_hex(v).map_err(|err| DeError::custom(format!("invalid hex string: {err}"))) } + + fn visit_bytes(self, v: &[u8]) -> Result { + let buf = <[u8; 32]>::try_from(v).map_err(serde::de::Error::custom)?; + + if U256::from_be_slice(&buf) < PRIME { + Ok(Felt::from_bytes_be(&buf)) + } else { + Err(serde::de::Error::custom("field element value out of range")) + } + } } impl SerializeAs> for UfeHexOption { @@ -56,9 +78,16 @@ impl SerializeAs> for UfeHexOption { where S: Serializer, { - match value { - Some(value) => serializer.serialize_str(&format!("{value:#064x}")), - None => serializer.serialize_none(), + if serializer.is_human_readable() { + match value { + Some(value) => serializer.serialize_str(&format!("{value:#064x}")), + None => serializer.serialize_none(), + } + } else { + match value { + Some(value) => serializer.serialize_bytes(&value.to_bytes_be()), + None => serializer.serialize_bytes(&[]), + } } } } @@ -68,7 +97,11 @@ impl<'de> DeserializeAs<'de, Option> for UfeHexOption { where D: Deserializer<'de>, { - deserializer.deserialize_any(UfeHexOptionVisitor) + if deserializer.is_human_readable() { + deserializer.deserialize_any(UfeHexOptionVisitor) + } else { + deserializer.deserialize_bytes(UfeHexOptionVisitor) + } } } @@ -91,6 +124,20 @@ impl<'de> Visitor<'de> for UfeHexOptionVisitor { }, } } + + fn visit_bytes(self, v: &[u8]) -> Result { + if v.is_empty() { + return Ok(None); + } + + let buf = <[u8; 32]>::try_from(v).map_err(serde::de::Error::custom)?; + + if U256::from_be_slice(&buf) < PRIME { + Ok(Some(Felt::from_bytes_be(&buf))) + } else { + Err(serde::de::Error::custom("field element value out of range")) + } + } } impl SerializeAs> for UfePendingBlockHash { @@ -98,10 +145,17 @@ impl SerializeAs> for UfePendingBlockHash { where S: Serializer, { - match value { - Some(value) => serializer.serialize_str(&format!("{value:#064x}")), - // We don't know if it's `null` or `"pending"` - None => serializer.serialize_none(), + if serializer.is_human_readable() { + match value { + Some(value) => serializer.serialize_str(&format!("{value:#064x}")), + // We don't know if it's `null` or `"pending"` + None => serializer.serialize_none(), + } + } else { + match value { + Some(value) => serializer.serialize_bytes(&value.to_bytes_be()), + None => serializer.serialize_bytes(&[]), + } } } } @@ -111,7 +165,11 @@ impl<'de> DeserializeAs<'de, Option> for UfePendingBlockHash { where D: Deserializer<'de>, { - deserializer.deserialize_any(UfePendingBlockHashVisitor) + if deserializer.is_human_readable() { + deserializer.deserialize_any(UfePendingBlockHashVisitor) + } else { + deserializer.deserialize_bytes(UfePendingBlockHashVisitor) + } } } @@ -135,23 +193,115 @@ impl<'de> Visitor<'de> for UfePendingBlockHashVisitor { } } } + + fn visit_bytes(self, v: &[u8]) -> Result { + if v.is_empty() { + return Ok(None); + } + + let buf = <[u8; 32]>::try_from(v).map_err(serde::de::Error::custom)?; + + if U256::from_be_slice(&buf) < PRIME { + Ok(Some(Felt::from_bytes_be(&buf))) + } else { + Err(serde::de::Error::custom("field element value out of range")) + } + } } #[cfg(test)] mod tests { use super::*; - use serde::Deserialize; + use hex_literal::hex; + use serde::{Deserialize, Serialize}; use serde_with::serde_as; #[serde_as] - #[derive(Deserialize)] - struct TestStruct(#[serde_as(as = "UfeHexOption")] pub Option); + #[derive(Serialize, Deserialize)] + struct TestStruct(#[serde_as(as = "UfeHex")] pub Felt); + + #[serde_as] + #[derive(Serialize, Deserialize)] + struct TestOptionStruct(#[serde_as(as = "UfeHexOption")] pub Option); + + #[serde_as] + #[derive(Serialize, Deserialize)] + struct TestBlockHashStruct(#[serde_as(as = "UfePendingBlockHash")] pub Option); + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_ser() { + let r = bincode::serialize(&TestStruct(Felt::ONE)).unwrap(); + assert_eq!( + r, + hex!( + "2000000000000000 0000000000000000000000000000000000000000000000000000000000000001" + ) + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_deser() { + let r = bincode::deserialize::(&hex!( + "2000000000000000 0000000000000000000000000000000000000000000000000000000000000001" + )) + .unwrap(); + assert_eq!(r.0, Felt::ONE); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_deser_out_of_range() { + if bincode::deserialize::(&hex!( + "2000000000000000 0800000000000011000000000000000000000000000000000000000000000001" + )) + .is_ok() + { + panic!("deserialization should fail") + } + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn option_deser_empty_string() { + let r = serde_json::from_str::("\"\"").unwrap(); + assert_eq!(r.0, None); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn option_bin_ser_none() { + let r = bincode::serialize(&TestOptionStruct(None)).unwrap(); + assert_eq!(r, hex!("0000000000000000")); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn option_bin_deser_none() { + let r = bincode::deserialize::(&hex!("0000000000000000")).unwrap(); + assert_eq!(r.0, None); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn pending_block_hash_deser_pending() { + let r = serde_json::from_str::("\"pending\"").unwrap(); + assert_eq!(r.0, None); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn pending_block_hash_bin_ser_none() { + let r = bincode::serialize(&TestBlockHashStruct(None)).unwrap(); + assert_eq!(r, hex!("0000000000000000")); + } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn empty_string_deser() { - let r = serde_json::from_str::("\"\"").unwrap(); + fn pending_block_hash_bin_deser_none() { + let r = bincode::deserialize::(&hex!("0000000000000000")).unwrap(); assert_eq!(r.0, None); } } diff --git a/starknet-core/src/types/hash_256.rs b/starknet-core/src/types/hash_256.rs index dd3e31d0..ec0bb839 100644 --- a/starknet-core/src/types/hash_256.rs +++ b/starknet-core/src/types/hash_256.rs @@ -78,7 +78,11 @@ impl Serialize for Hash256 { where S: serde::Serializer, { - serializer.serialize_str(&format!("0x{}", hex::encode(self.inner))) + if serializer.is_human_readable() { + serializer.serialize_str(&format!("0x{}", hex::encode(self.inner))) + } else { + serializer.serialize_bytes(self.as_bytes()) + } } } @@ -87,7 +91,11 @@ impl<'de> Deserialize<'de> for Hash256 { where D: serde::Deserializer<'de>, { - deserializer.deserialize_any(Hash256Visitor) + if deserializer.is_human_readable() { + deserializer.deserialize_any(Hash256Visitor) + } else { + deserializer.deserialize_bytes(Hash256Visitor) + } } } @@ -95,7 +103,7 @@ impl<'de> Visitor<'de> for Hash256Visitor { type Value = Hash256; fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { - write!(formatter, "string") + write!(formatter, "string, or an array of u8") } fn visit_str(self, v: &str) -> Result @@ -105,6 +113,12 @@ impl<'de> Visitor<'de> for Hash256Visitor { v.parse() .map_err(|err| serde::de::Error::custom(format!("{}", err))) } + + fn visit_bytes(self, v: &[u8]) -> Result { + <[u8; HASH_256_BYTE_COUNT]>::try_from(v) + .map(Hash256::from_bytes) + .map_err(serde::de::Error::custom) + } } impl FromStr for Hash256 { @@ -186,6 +200,8 @@ impl From<[u8; HASH_256_BYTE_COUNT]> for Hash256 { mod tests { use super::{Felt, FromHexError, Hash256, HASH_256_BYTE_COUNT}; + use hex_literal::hex; + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_hash_256_from_hex_error_unexpected_length() { @@ -243,4 +259,32 @@ mod tests { // Assert that the conversion from the `Felt` to `Hash256` is successful assert_eq!(Hash256::from_felt(&felt), hash_256); } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_ser() { + let r = bincode::serialize(&Hash256::from_bytes(hex!( + "1111111111111111111111111111111111111111111111111111111111111111" + ))) + .unwrap(); + assert_eq!( + r, + hex!( + "2000000000000000 1111111111111111111111111111111111111111111111111111111111111111" + ) + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_deser() { + let r = bincode::deserialize::(&hex!( + "2000000000000000 1111111111111111111111111111111111111111111111111111111111111111" + )) + .unwrap(); + assert_eq!( + r.inner, + hex!("1111111111111111111111111111111111111111111111111111111111111111") + ); + } } From bd7c62906a4a242fdc7ce0624ce8b4c5b6110760 Mon Sep 17 00:00:00 2001 From: Charpa <102919164+jbcaron@users.noreply.github.com> Date: Tue, 16 Jul 2024 06:33:20 +0200 Subject: [PATCH 16/54] feat(sequencer): add get_state_update_with_block (#597) --- starknet-providers/src/sequencer/mod.rs | 18 ++++++++++++++++++ starknet-providers/src/sequencer/models/mod.rs | 2 +- .../src/sequencer/models/state_update.rs | 10 ++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/starknet-providers/src/sequencer/mod.rs b/starknet-providers/src/sequencer/mod.rs index 74d05225..4453a3ed 100644 --- a/starknet-providers/src/sequencer/mod.rs +++ b/starknet-providers/src/sequencer/mod.rs @@ -313,6 +313,24 @@ impl SequencerGatewayProvider { .into() } + #[deprecated( + note = "Sequencer-specific functions are deprecated. Use it via the Provider trait instead." + )] + pub async fn get_state_update_with_block( + &self, + block_identifier: BlockId, + ) -> Result { + let mut request_url = self.extend_feeder_gateway_url("get_state_update"); + append_block_id(&mut request_url, block_identifier); + request_url + .query_pairs_mut() + .append_pair("includeBlock", "true"); + + self.send_get_request::>(request_url) + .await? + .into() + } + #[deprecated( note = "Sequencer-specific functions are deprecated. Use it via the Provider trait instead." )] diff --git a/starknet-providers/src/sequencer/models/mod.rs b/starknet-providers/src/sequencer/models/mod.rs index 3e269958..c1c0922e 100644 --- a/starknet-providers/src/sequencer/models/mod.rs +++ b/starknet-providers/src/sequencer/models/mod.rs @@ -46,7 +46,7 @@ mod contract; pub use contract::{CompressedLegacyContractClass, DeployedClass}; pub mod state_update; -pub use state_update::StateUpdate; +pub use state_update::{StateUpdate, StateUpdateWithBlock}; pub mod trace; pub use trace::{BlockTraces, TransactionTrace}; diff --git a/starknet-providers/src/sequencer/models/state_update.rs b/starknet-providers/src/sequencer/models/state_update.rs index 0447b96c..c0e56316 100644 --- a/starknet-providers/src/sequencer/models/state_update.rs +++ b/starknet-providers/src/sequencer/models/state_update.rs @@ -3,6 +3,16 @@ use serde_with::serde_as; use starknet_core::{serde::unsigned_field_element::UfeHex, types::Felt}; use std::collections::HashMap; +use super::Block; + +#[serde_as] +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] +pub struct StateUpdateWithBlock { + pub state_update: StateUpdate, + pub block: Block, +} + #[serde_as] #[derive(Debug, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] From a8ee4e28468ee28e384b105a5c4f92d10df73fbd Mon Sep 17 00:00:00 2001 From: Aniket Prajapati <46114123+aniketpr01@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:34:31 +0530 Subject: [PATCH 17/54] chore: more clippy lints (#598) --- Cargo.toml | 75 +++++++++ starknet-accounts/Cargo.toml | 3 + starknet-accounts/src/account/declaration.rs | 32 ++-- starknet-accounts/src/account/execution.rs | 20 +-- starknet-accounts/src/account/mod.rs | 45 +++--- starknet-accounts/src/factory/argent.rs | 1 + starknet-accounts/src/factory/mod.rs | 64 ++++---- .../src/factory/open_zeppelin.rs | 1 + starknet-accounts/src/single_owner.rs | 8 +- .../tests/single_owner_account.rs | 2 +- starknet-contract/Cargo.toml | 3 + starknet-contract/src/factory.rs | 35 +++-- .../tests/contract_deployment.rs | 4 +- starknet-core/Cargo.toml | 3 + starknet-core/src/chain_id.rs | 4 +- starknet-core/src/serde/byte_array.rs | 2 +- starknet-core/src/serde/num_hex.rs | 2 +- .../src/serde/unsigned_field_element.rs | 9 +- starknet-core/src/types/codegen.rs | 5 +- starknet-core/src/types/contract/legacy.rs | 22 ++- starknet-core/src/types/contract/mod.rs | 40 ++--- starknet-core/src/types/conversions.rs | 30 ++-- starknet-core/src/types/eth_address.rs | 6 +- starknet-core/src/types/execution_result.rs | 10 +- starknet-core/src/types/hash_256.rs | 10 +- starknet-core/src/types/mod.rs | 142 +++++++++--------- starknet-core/src/types/msg.rs | 8 +- starknet-core/src/types/receipt_block.rs | 24 +-- starknet-core/src/types/serde_impls.rs | 24 ++- starknet-core/src/types/u256.rs | 62 ++++---- starknet-core/src/utils.rs | 12 +- starknet-crypto-codegen/Cargo.toml | 3 + starknet-crypto/Cargo.toml | 3 + starknet-crypto/src/ecdsa.rs | 6 +- starknet-crypto/src/lib.rs | 1 + starknet-crypto/src/pedersen_hash.rs | 2 +- starknet-crypto/src/poseidon_hash.rs | 19 ++- starknet-crypto/src/rfc6979.rs | 4 +- starknet-curve/Cargo.toml | 3 + starknet-macros/Cargo.toml | 3 + starknet-macros/src/lib.rs | 2 +- starknet-providers/Cargo.toml | 3 + starknet-providers/src/any.rs | 2 +- starknet-providers/src/jsonrpc/mod.rs | 56 +++---- .../src/jsonrpc/transports/http.rs | 6 +- starknet-providers/src/provider.rs | 4 +- starknet-providers/src/sequencer/mod.rs | 40 +++-- .../src/sequencer/models/contract.rs | 2 +- .../src/sequencer/models/conversions.rs | 7 +- .../src/sequencer/models/serde_impls.rs | 6 +- .../src/sequencer/models/transaction.rs | 14 +- starknet-providers/src/sequencer/provider.rs | 5 +- starknet-providers/tests/jsonrpc.rs | 2 +- starknet-signers/Cargo.toml | 3 + starknet-signers/src/key_pair.rs | 8 +- 55 files changed, 504 insertions(+), 408 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b3c0f9cc..cb1a68f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,3 +54,78 @@ no_unknown_fields = [ "starknet-core/no_unknown_fields", "starknet-providers/no_unknown_fields", ] + +[workspace.lints] +rust.missing_debug_implementations = "warn" +rust.missing_docs = "allow" +rust.unreachable_pub = "allow" +rust.unused_must_use = "deny" +rust.rust_2018_idioms = { level = "deny", priority = -1 } +rustdoc.all = "warn" + +[workspace.lints.clippy] +# These are some of clippy's nursery (i.e., experimental) lints that we like. +# By default, nursery lints are allowed. Some of the lints below have made good +# suggestions which we fixed. The others didn't have any findings, so we can +# assume they don't have that many false positives. Let's enable them to +# prevent future problems. +branches_sharing_code = "warn" +clear_with_drain = "warn" +derive_partial_eq_without_eq = "warn" +empty_line_after_outer_attr = "warn" +equatable_if_let = "warn" +imprecise_flops = "warn" +iter_on_empty_collections = "warn" +iter_with_drain = "warn" +large_stack_frames = "warn" +manual_clamp = "warn" +mutex_integer = "warn" +needless_pass_by_ref_mut = "warn" +nonstandard_macro_braces = "warn" +or_fun_call = "warn" +path_buf_push_overwrite = "warn" +read_zero_byte_vec = "warn" +redundant_clone = "warn" +suboptimal_flops = "warn" +suspicious_operation_groupings = "warn" +trailing_empty_array = "warn" +trait_duplication_in_bounds = "warn" +transmute_undefined_repr = "warn" +trivial_regex = "warn" +tuple_array_conversions = "warn" +uninhabited_references = "warn" +unused_peekable = "warn" +unused_rounding = "warn" +useless_let_if_seq = "warn" +use_self = "warn" +missing_const_for_fn = "warn" +empty_line_after_doc_comments = "warn" +iter_on_single_items = "warn" +match_same_arms = "warn" +doc_markdown = "warn" +unnecessary_struct_initialization = "warn" +string_lit_as_bytes = "warn" +explicit_into_iter_loop = "warn" +explicit_iter_loop = "warn" +type_repetition_in_bounds = "allow" +manual_string_new = "warn" +naive_bytecount = "warn" +needless_bitwise_bool = "warn" +zero_sized_map_values = "warn" +single_char_pattern = "warn" +needless_continue = "warn" + +# These are nursery lints which have findings. Allow them for now. Some are not +# quite mature enough for use in our codebase and some we don't really want. +# Explicitly listing should make it easier to fix in the future. +as_ptr_cast_mut = "allow" +cognitive_complexity = "allow" +collection_is_never_read = "allow" +debug_assert_with_mut_call = "allow" +fallible_impl_from = "allow" +future_not_send = "allow" +needless_collect = "allow" +non_send_fields_in_send_ty = "allow" +redundant_pub_crate = "allow" +significant_drop_in_scrutinee = "allow" +significant_drop_tightening = "allow" diff --git a/starknet-accounts/Cargo.toml b/starknet-accounts/Cargo.toml index 6ad3ad82..442a53fe 100644 --- a/starknet-accounts/Cargo.toml +++ b/starknet-accounts/Cargo.toml @@ -27,3 +27,6 @@ serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0.96" tokio = { version = "1.27.0", features = ["full"] } url = "2.3.1" + +[lints] +workspace = true diff --git a/starknet-accounts/src/account/declaration.rs b/starknet-accounts/src/account/declaration.rs index 360dc924..d8d2de4e 100644 --- a/starknet-accounts/src/account/declaration.rs +++ b/starknet-accounts/src/account/declaration.rs @@ -52,7 +52,7 @@ const QUERY_VERSION_THREE: Felt = Felt::from_raw([ ]); impl<'a, A> DeclarationV2<'a, A> { - pub fn new( + pub const fn new( contract_class: Arc, compiled_class_hash: Felt, account: &'a A, @@ -88,8 +88,8 @@ impl<'a, A> DeclarationV2<'a, A> { } } - /// Calling this function after manually specifying `nonce` and `max_fee` turns [DeclarationV2] - /// into [PreparedDeclarationV2]. Returns `Err` if either field is `None`. + /// Calling this function after manually specifying `nonce` and `max_fee` turns [`DeclarationV2`] + /// into [`PreparedDeclarationV2`]. Returns `Err` if either field is `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; let max_fee = self.max_fee.ok_or(NotPreparedError)?; @@ -275,7 +275,7 @@ where } impl<'a, A> DeclarationV3<'a, A> { - pub fn new( + pub const fn new( contract_class: Arc, compiled_class_hash: Felt, account: &'a A, @@ -328,7 +328,7 @@ impl<'a, A> DeclarationV3<'a, A> { } /// Calling this function after manually specifying `nonce`, `gas` and `gas_price` turns - /// [DeclarationV3] into [PreparedDeclarationV3]. Returns `Err` if any field is `None`. + /// [`DeclarationV3`] into [`PreparedDeclarationV3`]. Returns `Err` if any field is `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; let gas = self.gas.ok_or(NotPreparedError)?; @@ -570,7 +570,7 @@ where } impl<'a, A> LegacyDeclaration<'a, A> { - pub fn new(contract_class: Arc, account: &'a A) -> Self { + pub const fn new(contract_class: Arc, account: &'a A) -> Self { Self { account, contract_class, @@ -602,7 +602,7 @@ impl<'a, A> LegacyDeclaration<'a, A> { } /// Calling this function after manually specifying `nonce` and `max_fee` turns - /// [LegacyDeclaration] into [PreparedLegacyDeclaration]. Returns `Err` if either field is + /// [`LegacyDeclaration`] into [`PreparedLegacyDeclaration`]. Returns `Err` if either field is /// `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; @@ -809,15 +809,15 @@ impl RawDeclarationV2 { &self.contract_class } - pub fn compiled_class_hash(&self) -> Felt { + pub const fn compiled_class_hash(&self) -> Felt { self.compiled_class_hash } - pub fn nonce(&self) -> Felt { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn max_fee(&self) -> Felt { + pub const fn max_fee(&self) -> Felt { self.max_fee } } @@ -880,19 +880,19 @@ impl RawDeclarationV3 { &self.contract_class } - pub fn compiled_class_hash(&self) -> Felt { + pub const fn compiled_class_hash(&self) -> Felt { self.compiled_class_hash } - pub fn nonce(&self) -> Felt { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn gas(&self) -> u64 { + pub const fn gas(&self) -> u64 { self.gas } - pub fn gas_price(&self) -> u128 { + pub const fn gas_price(&self) -> u128 { self.gas_price } } @@ -924,11 +924,11 @@ impl RawLegacyDeclaration { &self.contract_class } - pub fn nonce(&self) -> Felt { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn max_fee(&self) -> Felt { + pub const fn max_fee(&self) -> Felt { self.max_fee } } diff --git a/starknet-accounts/src/account/execution.rs b/starknet-accounts/src/account/execution.rs index 99757da0..3e529a45 100644 --- a/starknet-accounts/src/account/execution.rs +++ b/starknet-accounts/src/account/execution.rs @@ -41,7 +41,7 @@ const QUERY_VERSION_THREE: Felt = Felt::from_raw([ ]); impl<'a, A> ExecutionV1<'a, A> { - pub fn new(calls: Vec, account: &'a A) -> Self { + pub const fn new(calls: Vec, account: &'a A) -> Self { Self { account, calls, @@ -72,8 +72,8 @@ impl<'a, A> ExecutionV1<'a, A> { } } - /// Calling this function after manually specifying `nonce` and `max_fee` turns [ExecutionV1] into - /// [PreparedExecutionV1]. Returns `Err` if either field is `None`. + /// Calling this function after manually specifying `nonce` and `max_fee` turns [`ExecutionV1`] into + /// [`PreparedExecutionV1`]. Returns `Err` if either field is `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; let max_fee = self.max_fee.ok_or(NotPreparedError)?; @@ -90,7 +90,7 @@ impl<'a, A> ExecutionV1<'a, A> { } impl<'a, A> ExecutionV3<'a, A> { - pub fn new(calls: Vec, account: &'a A) -> Self { + pub const fn new(calls: Vec, account: &'a A) -> Self { Self { account, calls, @@ -138,7 +138,7 @@ impl<'a, A> ExecutionV3<'a, A> { } /// Calling this function after manually specifying `nonce`, `gas` and `gas_price` turns - /// [ExecutionV3] into [PreparedExecutionV3]. Returns `Err` if any field is `None`. + /// [`ExecutionV3`] into [`PreparedExecutionV3`]. Returns `Err` if any field is `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; let gas = self.gas.ok_or(NotPreparedError)?; @@ -583,11 +583,11 @@ impl RawExecutionV1 { &self.calls } - pub fn nonce(&self) -> Felt { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn max_fee(&self) -> Felt { + pub const fn max_fee(&self) -> Felt { self.max_fee } } @@ -667,15 +667,15 @@ impl RawExecutionV3 { &self.calls } - pub fn nonce(&self) -> Felt { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn gas(&self) -> u64 { + pub const fn gas(&self) -> u64 { self.gas } - pub fn gas_price(&self) -> u128 { + pub const fn gas_price(&self) -> u128 { self.gas_price } } diff --git a/starknet-accounts/src/account/mod.rs b/starknet-accounts/src/account/mod.rs index 94c9031c..5bb2db3e 100644 --- a/starknet-accounts/src/account/mod.rs +++ b/starknet-accounts/src/account/mod.rs @@ -63,16 +63,16 @@ pub trait Account: ExecutionEncoder + Sized { /// estimation/simulation purposes. fn is_signer_interactive(&self) -> bool; - fn execute_v1(&self, calls: Vec) -> ExecutionV1 { + fn execute_v1(&self, calls: Vec) -> ExecutionV1<'_, Self> { ExecutionV1::new(calls, self) } - fn execute_v3(&self, calls: Vec) -> ExecutionV3 { + fn execute_v3(&self, calls: Vec) -> ExecutionV3<'_, Self> { ExecutionV3::new(calls, self) } #[deprecated = "use version specific variants (`execute_v1` & `execute_v3`) instead"] - fn execute(&self, calls: Vec) -> ExecutionV1 { + fn execute(&self, calls: Vec) -> ExecutionV1<'_, Self> { self.execute_v1(calls) } @@ -80,7 +80,7 @@ pub trait Account: ExecutionEncoder + Sized { &self, contract_class: Arc, compiled_class_hash: Felt, - ) -> DeclarationV2 { + ) -> DeclarationV2<'_, Self> { DeclarationV2::new(contract_class, compiled_class_hash, self) } @@ -88,7 +88,7 @@ pub trait Account: ExecutionEncoder + Sized { &self, contract_class: Arc, compiled_class_hash: Felt, - ) -> DeclarationV3 { + ) -> DeclarationV3<'_, Self> { DeclarationV3::new(contract_class, compiled_class_hash, self) } @@ -97,11 +97,14 @@ pub trait Account: ExecutionEncoder + Sized { &self, contract_class: Arc, compiled_class_hash: Felt, - ) -> DeclarationV2 { + ) -> DeclarationV2<'_, Self> { self.declare_v2(contract_class, compiled_class_hash) } - fn declare_legacy(&self, contract_class: Arc) -> LegacyDeclaration { + fn declare_legacy( + &self, + contract_class: Arc, + ) -> LegacyDeclaration<'_, Self> { LegacyDeclaration::new(contract_class, self) } } @@ -135,7 +138,7 @@ pub trait ConnectedAccount: Account { /// Abstraction over `INVOKE` transactions from accounts for invoking contracts. This struct uses /// v1 `INVOKE` transactions under the hood, and hence pays transaction fees in ETH. To use v3 -/// transactions for STRK fee payment, use [ExecutionV3] instead. +/// transactions for STRK fee payment, use [`ExecutionV3`] instead. /// /// This is an intermediate type allowing users to optionally specify `nonce` and/or `max_fee`. #[must_use] @@ -150,7 +153,7 @@ pub struct ExecutionV1<'a, A> { /// Abstraction over `INVOKE` transactions from accounts for invoking contracts. This struct uses /// v3 `INVOKE` transactions under the hood, and hence pays transaction fees in STRK. To use v1 -/// transactions for ETH fee payment, use [ExecutionV1] instead. +/// transactions for ETH fee payment, use [`ExecutionV1`] instead. /// /// This is an intermediate type allowing users to optionally specify `nonce`, `gas`, and/or /// `gas_price`. @@ -168,7 +171,7 @@ pub struct ExecutionV3<'a, A> { /// Abstraction over `DECLARE` transactions from accounts for invoking contracts. This struct uses /// v2 `DECLARE` transactions under the hood, and hence pays transaction fees in ETH. To use v3 -/// transactions for STRK fee payment, use [DeclarationV3] instead. +/// transactions for STRK fee payment, use [`DeclarationV3`] instead. /// /// An intermediate type allowing users to optionally specify `nonce` and/or `max_fee`. #[must_use] @@ -184,7 +187,7 @@ pub struct DeclarationV2<'a, A> { /// Abstraction over `DECLARE` transactions from accounts for invoking contracts. This struct uses /// v3 `DECLARE` transactions under the hood, and hence pays transaction fees in STRK. To use v2 -/// transactions for ETH fee payment, use [DeclarationV2] instead. +/// transactions for ETH fee payment, use [`DeclarationV2`] instead. /// /// This is an intermediate type allowing users to optionally specify `nonce`, `gas`, and/or /// `gas_price`. @@ -212,7 +215,7 @@ pub struct LegacyDeclaration<'a, A> { fee_estimate_multiplier: f64, } -/// [ExecutionV1] but with `nonce` and `max_fee` already determined. +/// [`ExecutionV1`] but with `nonce` and `max_fee` already determined. #[derive(Debug)] pub struct RawExecutionV1 { calls: Vec, @@ -220,7 +223,7 @@ pub struct RawExecutionV1 { max_fee: Felt, } -/// [ExecutionV3] but with `nonce`, `gas` and `gas_price` already determined. +/// [`ExecutionV3`] but with `nonce`, `gas` and `gas_price` already determined. #[derive(Debug)] pub struct RawExecutionV3 { calls: Vec, @@ -229,7 +232,7 @@ pub struct RawExecutionV3 { gas_price: u128, } -/// [DeclarationV2] but with `nonce` and `max_fee` already determined. +/// [`DeclarationV2`] but with `nonce` and `max_fee` already determined. #[derive(Debug)] pub struct RawDeclarationV2 { contract_class: Arc, @@ -238,7 +241,7 @@ pub struct RawDeclarationV2 { max_fee: Felt, } -/// [DeclarationV3] but with `nonce`, `gas` and `gas_price` already determined. +/// [`DeclarationV3`] but with `nonce`, `gas` and `gas_price` already determined. #[derive(Debug)] pub struct RawDeclarationV3 { contract_class: Arc, @@ -248,7 +251,7 @@ pub struct RawDeclarationV3 { gas_price: u128, } -/// [LegacyDeclaration] but with `nonce` and `max_fee` already determined. +/// [`LegacyDeclaration`] but with `nonce` and `max_fee` already determined. #[derive(Debug)] pub struct RawLegacyDeclaration { contract_class: Arc, @@ -256,35 +259,35 @@ pub struct RawLegacyDeclaration { max_fee: Felt, } -/// [RawExecutionV1] but with an account associated. +/// [`RawExecutionV1`] but with an account associated. #[derive(Debug)] pub struct PreparedExecutionV1<'a, A> { account: &'a A, inner: RawExecutionV1, } -/// [RawExecutionV3] but with an account associated. +/// [`RawExecutionV3`] but with an account associated. #[derive(Debug)] pub struct PreparedExecutionV3<'a, A> { account: &'a A, inner: RawExecutionV3, } -/// [RawDeclarationV2] but with an account associated. +/// [`RawDeclarationV2`] but with an account associated. #[derive(Debug)] pub struct PreparedDeclarationV2<'a, A> { account: &'a A, inner: RawDeclarationV2, } -/// [RawDeclarationV3] but with an account associated. +/// [`RawDeclarationV3`] but with an account associated. #[derive(Debug)] pub struct PreparedDeclarationV3<'a, A> { account: &'a A, inner: RawDeclarationV3, } -/// [RawLegacyDeclaration] but with an account associated. +/// [`RawLegacyDeclaration`] but with an account associated. #[derive(Debug)] pub struct PreparedLegacyDeclaration<'a, A> { account: &'a A, diff --git a/starknet-accounts/src/factory/argent.rs b/starknet-accounts/src/factory/argent.rs index 5bfa0476..a8cf6482 100644 --- a/starknet-accounts/src/factory/argent.rs +++ b/starknet-accounts/src/factory/argent.rs @@ -8,6 +8,7 @@ use starknet_core::types::{BlockId, BlockTag, Felt}; use starknet_providers::Provider; use starknet_signers::Signer; +#[derive(Debug)] pub struct ArgentAccountFactory { class_hash: Felt, chain_id: Felt, diff --git a/starknet-accounts/src/factory/mod.rs b/starknet-accounts/src/factory/mod.rs index 1dc3b773..17f3d2a2 100644 --- a/starknet-accounts/src/factory/mod.rs +++ b/starknet-accounts/src/factory/mod.rs @@ -18,7 +18,7 @@ use std::error::Error; pub mod argent; pub mod open_zeppelin; -/// Cairo string for "deploy_account" +/// Cairo string for `deploy_account` const PREFIX_DEPLOY_ACCOUNT: Felt = Felt::from_raw([ 461298303000467581, 18446744073709551615, @@ -42,7 +42,7 @@ const QUERY_VERSION_THREE: Felt = Felt::from_raw([ 18446744073700081569, ]); -/// Cairo string for "STARKNET_CONTRACT_ADDRESS" +/// Cairo string for `STARKNET_CONTRACT_ADDRESS` const PREFIX_CONTRACT_ADDRESS: Felt = Felt::from_raw([ 533439743893157637, 8635008616843941496, @@ -98,23 +98,23 @@ pub trait AccountFactory: Sized { query_only: bool, ) -> Result, Self::SignError>; - fn deploy_v1(&self, salt: Felt) -> AccountDeploymentV1 { + fn deploy_v1(&self, salt: Felt) -> AccountDeploymentV1<'_, Self> { AccountDeploymentV1::new(salt, self) } - fn deploy_v3(&self, salt: Felt) -> AccountDeploymentV3 { + fn deploy_v3(&self, salt: Felt) -> AccountDeploymentV3<'_, Self> { AccountDeploymentV3::new(salt, self) } #[deprecated = "use version specific variants (`deploy_v1` & `deploy_v3`) instead"] - fn deploy(&self, salt: Felt) -> AccountDeploymentV1 { + fn deploy(&self, salt: Felt) -> AccountDeploymentV1<'_, Self> { self.deploy_v1(salt) } } /// Abstraction over `DEPLOY_ACCOUNT` transactions for account contract deployment. This struct uses /// v1 `DEPLOY_ACCOUNT` transactions under the hood, and hence pays transaction fees in ETH. To use -/// v3 transactions for STRK fee payment, use [AccountDeploymentV3] instead. +/// v3 transactions for STRK fee payment, use [`AccountDeploymentV3`] instead. /// /// An intermediate type allowing users to optionally specify `nonce` and/or `max_fee`. #[must_use] @@ -131,7 +131,7 @@ pub struct AccountDeploymentV1<'f, F> { /// Abstraction over `DEPLOY_ACCOUNT` transactions for account contract deployment. This struct uses /// v3 `DEPLOY_ACCOUNT` transactions under the hood, and hence pays transaction fees in STRK. To use -/// v1 transactions for ETH fee payment, use [AccountDeploymentV1] instead. +/// v1 transactions for ETH fee payment, use [`AccountDeploymentV1`] instead. /// /// This is an intermediate type allowing users to optionally specify `nonce`, `gas`, and/or /// `gas_price`. @@ -149,7 +149,7 @@ pub struct AccountDeploymentV3<'f, F> { gas_price_estimate_multiplier: f64, } -/// [AccountDeploymentV1] but with `nonce` and `max_fee` already determined. +/// [`AccountDeploymentV1`] but with `nonce` and `max_fee` already determined. #[derive(Debug, Clone)] pub struct RawAccountDeploymentV1 { salt: Felt, @@ -157,7 +157,7 @@ pub struct RawAccountDeploymentV1 { max_fee: Felt, } -/// [AccountDeploymentV3] but with `nonce`, `gas` and `gas_price` already determined. +/// [`AccountDeploymentV3`] but with `nonce`, `gas` and `gas_price` already determined. #[derive(Debug, Clone)] pub struct RawAccountDeploymentV3 { salt: Felt, @@ -166,14 +166,14 @@ pub struct RawAccountDeploymentV3 { gas_price: u128, } -/// [RawAccountDeploymentV1] but with a factory associated. +/// [`RawAccountDeploymentV1`] but with a factory associated. #[derive(Debug)] pub struct PreparedAccountDeploymentV1<'f, F> { factory: &'f F, inner: RawAccountDeploymentV1, } -/// [RawAccountDeploymentV3] but with a factory associated. +/// [`RawAccountDeploymentV3`] but with a factory associated. #[derive(Debug)] pub struct PreparedAccountDeploymentV3<'f, F> { factory: &'f F, @@ -191,7 +191,7 @@ pub enum AccountFactoryError { } impl<'f, F> AccountDeploymentV1<'f, F> { - pub fn new(salt: Felt, factory: &'f F) -> Self { + pub const fn new(salt: Felt, factory: &'f F) -> Self { Self { factory, salt, @@ -201,21 +201,21 @@ impl<'f, F> AccountDeploymentV1<'f, F> { } } - pub fn nonce(self, nonce: Felt) -> Self { + pub const fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), ..self } } - pub fn max_fee(self, max_fee: Felt) -> Self { + pub const fn max_fee(self, max_fee: Felt) -> Self { Self { max_fee: Some(max_fee), ..self } } - pub fn fee_estimate_multiplier(self, fee_estimate_multiplier: f64) -> Self { + pub const fn fee_estimate_multiplier(self, fee_estimate_multiplier: f64) -> Self { Self { fee_estimate_multiplier, ..self @@ -223,7 +223,7 @@ impl<'f, F> AccountDeploymentV1<'f, F> { } /// Calling this function after manually specifying `nonce` and `max_fee` turns - /// [AccountDeploymentV1] into [PreparedAccountDeploymentV1]. Returns `Err` if either field is + /// [`AccountDeploymentV1`] into [`PreparedAccountDeploymentV1`]. Returns `Err` if either field is /// `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; @@ -241,7 +241,7 @@ impl<'f, F> AccountDeploymentV1<'f, F> { } impl<'f, F> AccountDeploymentV3<'f, F> { - pub fn new(salt: Felt, factory: &'f F) -> Self { + pub const fn new(salt: Felt, factory: &'f F) -> Self { Self { factory, salt, @@ -253,35 +253,35 @@ impl<'f, F> AccountDeploymentV3<'f, F> { } } - pub fn nonce(self, nonce: Felt) -> Self { + pub const fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), ..self } } - pub fn gas(self, gas: u64) -> Self { + pub const fn gas(self, gas: u64) -> Self { Self { gas: Some(gas), ..self } } - pub fn gas_price(self, gas_price: u128) -> Self { + pub const fn gas_price(self, gas_price: u128) -> Self { Self { gas_price: Some(gas_price), ..self } } - pub fn gas_estimate_multiplier(self, gas_estimate_multiplier: f64) -> Self { + pub const fn gas_estimate_multiplier(self, gas_estimate_multiplier: f64) -> Self { Self { gas_estimate_multiplier, ..self } } - pub fn gas_price_estimate_multiplier(self, gas_price_estimate_multiplier: f64) -> Self { + pub const fn gas_price_estimate_multiplier(self, gas_price_estimate_multiplier: f64) -> Self { Self { gas_price_estimate_multiplier, ..self @@ -289,7 +289,7 @@ impl<'f, F> AccountDeploymentV3<'f, F> { } /// Calling this function after manually specifying `nonce` and `max_fee` turns - /// [AccountDeploymentV3] into [PreparedAccountDeploymentV3]. Returns `Err` if either field is + /// [`AccountDeploymentV3`] into [`PreparedAccountDeploymentV3`]. Returns `Err` if either field is /// `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; @@ -760,39 +760,39 @@ where } impl RawAccountDeploymentV1 { - pub fn salt(&self) -> Felt { + pub const fn salt(&self) -> Felt { self.salt } - pub fn nonce(&self) -> Felt { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn max_fee(&self) -> Felt { + pub const fn max_fee(&self) -> Felt { self.max_fee } } impl RawAccountDeploymentV3 { - pub fn salt(&self) -> Felt { + pub const fn salt(&self) -> Felt { self.salt } - pub fn nonce(&self) -> Felt { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn gas(&self) -> u64 { + pub const fn gas(&self) -> u64 { self.gas } - pub fn gas_price(&self) -> u128 { + pub const fn gas_price(&self) -> u128 { self.gas_price } } impl<'f, F> PreparedAccountDeploymentV1<'f, F> { - pub fn from_raw(raw_deployment: RawAccountDeploymentV1, factory: &'f F) -> Self { + pub const fn from_raw(raw_deployment: RawAccountDeploymentV1, factory: &'f F) -> Self { Self { factory, inner: raw_deployment, @@ -801,7 +801,7 @@ impl<'f, F> PreparedAccountDeploymentV1<'f, F> { } impl<'f, F> PreparedAccountDeploymentV3<'f, F> { - pub fn from_raw(raw_deployment: RawAccountDeploymentV3, factory: &'f F) -> Self { + pub const fn from_raw(raw_deployment: RawAccountDeploymentV3, factory: &'f F) -> Self { Self { factory, inner: raw_deployment, diff --git a/starknet-accounts/src/factory/open_zeppelin.rs b/starknet-accounts/src/factory/open_zeppelin.rs index 3b23b16e..8fa95022 100644 --- a/starknet-accounts/src/factory/open_zeppelin.rs +++ b/starknet-accounts/src/factory/open_zeppelin.rs @@ -8,6 +8,7 @@ use starknet_core::types::{BlockId, BlockTag, Felt}; use starknet_providers::Provider; use starknet_signers::Signer; +#[derive(Debug)] pub struct OpenZeppelinAccountFactory { class_hash: Felt, chain_id: Felt, diff --git a/starknet-accounts/src/single_owner.rs b/starknet-accounts/src/single_owner.rs index 0677a8d8..4fc44ede 100644 --- a/starknet-accounts/src/single_owner.rs +++ b/starknet-accounts/src/single_owner.rs @@ -54,7 +54,7 @@ where /// * `address`: Account contract address. /// * `chain_id`: Network chain ID. /// * `encoding`: How `__execute__` calldata should be encoded. - pub fn new( + pub const fn new( provider: P, signer: S, address: Felt, @@ -187,13 +187,13 @@ where match self.encoding { ExecutionEncoding::Legacy => { let mut concated_calldata: Vec = vec![]; - for call in calls.iter() { + for call in calls { execute_calldata.push(call.to); // to execute_calldata.push(call.selector); // selector execute_calldata.push(concated_calldata.len().into()); // data_offset execute_calldata.push(call.calldata.len().into()); // data_len - for item in call.calldata.iter() { + for item in &call.calldata { concated_calldata.push(*item); } } @@ -202,7 +202,7 @@ where execute_calldata.extend_from_slice(&concated_calldata); } ExecutionEncoding::New => { - for call in calls.iter() { + for call in calls { execute_calldata.push(call.to); // to execute_calldata.push(call.selector); // selector diff --git a/starknet-accounts/tests/single_owner_account.rs b/starknet-accounts/tests/single_owner_account.rs index c779c491..46d895f4 100644 --- a/starknet-accounts/tests/single_owner_account.rs +++ b/starknet-accounts/tests/single_owner_account.rs @@ -32,7 +32,7 @@ fn create_sequencer_client() -> SequencerGatewayProvider { fn create_jsonrpc_client() -> JsonRpcClient { let rpc_url = std::env::var("STARKNET_RPC") - .unwrap_or("https://juno.rpc.sepolia.starknet.rs/rpc/v0_7".into()); + .unwrap_or_else(|_| "https://juno.rpc.sepolia.starknet.rs/rpc/v0_7".into()); JsonRpcClient::new(HttpTransport::new(url::Url::parse(&rpc_url).unwrap())) } diff --git a/starknet-contract/Cargo.toml b/starknet-contract/Cargo.toml index 1c44ac28..f6a89f3c 100644 --- a/starknet-contract/Cargo.toml +++ b/starknet-contract/Cargo.toml @@ -27,3 +27,6 @@ rand = { version = "0.8.5", features=["std_rng"] } starknet-signers = { version = "0.9.0", path = "../starknet-signers" } tokio = { version = "1.27.0", features = ["full"] } url = "2.3.1" + +[lints] +workspace = true diff --git a/starknet-contract/src/factory.rs b/starknet-contract/src/factory.rs index 0cbd6065..299ff0f1 100644 --- a/starknet-contract/src/factory.rs +++ b/starknet-contract/src/factory.rs @@ -20,6 +20,7 @@ const SELECTOR_DEPLOYCONTRACT: Felt = Felt::from_raw([ 18249998464715511309, ]); +#[derive(Debug)] pub struct ContractFactory { class_hash: Felt, udc_address: Felt, @@ -28,8 +29,9 @@ pub struct ContractFactory { /// Abstraction over contract deployment via the UDC. This type uses `INVOKE` v1 transactions under /// the hood, and hence pays transaction fees in ETH. To use v3 transactions for STRK fee payment, -/// use [DeploymentV3] instead. +/// use [`DeploymentV3`] instead. #[must_use] +#[derive(Debug)] pub struct DeploymentV1<'f, A> { factory: &'f ContractFactory, constructor_calldata: Vec, @@ -43,8 +45,9 @@ pub struct DeploymentV1<'f, A> { /// Abstraction over contract deployment via the UDC. This type uses `INVOKE` v3 transactions under /// the hood, and hence pays transaction fees in STRK. To use v1 transactions for ETH fee payment, -/// use [DeploymentV1] instead. +/// use [`DeploymentV1`] instead. #[must_use] +#[derive(Debug)] pub struct DeploymentV3<'f, A> { factory: &'f ContractFactory, constructor_calldata: Vec, @@ -59,11 +62,11 @@ pub struct DeploymentV3<'f, A> { } impl ContractFactory { - pub fn new(class_hash: Felt, account: A) -> Self { + pub const fn new(class_hash: Felt, account: A) -> Self { Self::new_with_udc(class_hash, account, UDC_ADDRESS) } - pub fn new_with_udc(class_hash: Felt, account: A, udc_address: Felt) -> Self { + pub const fn new_with_udc(class_hash: Felt, account: A, udc_address: Felt) -> Self { Self { class_hash, udc_address, @@ -76,12 +79,12 @@ impl ContractFactory where A: Account, { - pub fn deploy_v1( + pub const fn deploy_v1( &self, constructor_calldata: Vec, salt: Felt, unique: bool, - ) -> DeploymentV1 { + ) -> DeploymentV1<'_, A> { DeploymentV1 { factory: self, constructor_calldata, @@ -93,12 +96,12 @@ where } } - pub fn deploy_v3( + pub const fn deploy_v3( &self, constructor_calldata: Vec, salt: Felt, unique: bool, - ) -> DeploymentV3 { + ) -> DeploymentV3<'_, A> { DeploymentV3 { factory: self, constructor_calldata, @@ -113,12 +116,12 @@ where } #[deprecated = "use version specific variants (`deploy_v1` & `deploy_v3`) instead"] - pub fn deploy( + pub const fn deploy( &self, constructor_calldata: Vec, salt: Felt, unique: bool, - ) -> DeploymentV1 { + ) -> DeploymentV1<'_, A> { self.deploy_v1(constructor_calldata, salt, unique) } } @@ -232,7 +235,7 @@ where A: ConnectedAccount + Sync, { pub async fn estimate_fee(&self) -> Result> { - let execution: ExecutionV1 = self.into(); + let execution: ExecutionV1<'_, A> = self.into(); execution.estimate_fee().await } @@ -241,12 +244,12 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { - let execution: ExecutionV1 = self.into(); + let execution: ExecutionV1<'_, A> = self.into(); execution.simulate(skip_validate, skip_fee_charge).await } pub async fn send(&self) -> Result> { - let execution: ExecutionV1 = self.into(); + let execution: ExecutionV1<'_, A> = self.into(); execution.send().await } } @@ -256,7 +259,7 @@ where A: ConnectedAccount + Sync, { pub async fn estimate_fee(&self) -> Result> { - let execution: ExecutionV3 = self.into(); + let execution: ExecutionV3<'_, A> = self.into(); execution.estimate_fee().await } @@ -265,12 +268,12 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { - let execution: ExecutionV3 = self.into(); + let execution: ExecutionV3<'_, A> = self.into(); execution.simulate(skip_validate, skip_fee_charge).await } pub async fn send(&self) -> Result> { - let execution: ExecutionV3 = self.into(); + let execution: ExecutionV3<'_, A> = self.into(); execution.send().await } } diff --git a/starknet-contract/tests/contract_deployment.rs b/starknet-contract/tests/contract_deployment.rs index 14ab3f26..eff7f2cc 100644 --- a/starknet-contract/tests/contract_deployment.rs +++ b/starknet-contract/tests/contract_deployment.rs @@ -17,7 +17,7 @@ const CHAIN_ID: Felt = Felt::from_raw([ #[tokio::test] async fn can_deploy_contract_to_alpha_sepolia_with_invoke_v1() { let rpc_url = std::env::var("STARKNET_RPC") - .unwrap_or("https://pathfinder.rpc.sepolia.starknet.rs/rpc/v0_6".into()); + .unwrap_or_else(|_| "https://pathfinder.rpc.sepolia.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( Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), @@ -55,7 +55,7 @@ async fn can_deploy_contract_to_alpha_sepolia_with_invoke_v1() { #[tokio::test] async fn can_deploy_contract_to_alpha_sepolia_with_invoke_v3() { let rpc_url = std::env::var("STARKNET_RPC") - .unwrap_or("https://pathfinder.rpc.sepolia.starknet.rs/rpc/v0_6".into()); + .unwrap_or_else(|_| "https://pathfinder.rpc.sepolia.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( Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), diff --git a/starknet-core/Cargo.toml b/starknet-core/Cargo.toml index a035ded2..363ca0c7 100644 --- a/starknet-core/Cargo.toml +++ b/starknet-core/Cargo.toml @@ -50,3 +50,6 @@ harness = false [[bench]] name = "sierra_class_hash" harness = false + +[lints] +workspace = true diff --git a/starknet-core/src/chain_id.rs b/starknet-core/src/chain_id.rs index cbb430fa..715dc437 100644 --- a/starknet-core/src/chain_id.rs +++ b/starknet-core/src/chain_id.rs @@ -45,9 +45,7 @@ mod test { ("SN_GOERLI", TESTNET), ("SN_GOERLI2", TESTNET2), ("SN_SEPOLIA", SEPOLIA), - ] - .into_iter() - { + ] { assert_eq!(cairo_short_string_to_felt(text).unwrap(), felt); } } diff --git a/starknet-core/src/serde/byte_array.rs b/starknet-core/src/serde/byte_array.rs index 9d171396..0d2bb46e 100644 --- a/starknet-core/src/serde/byte_array.rs +++ b/starknet-core/src/serde/byte_array.rs @@ -24,7 +24,7 @@ pub mod base64 { impl<'de> Visitor<'de> for Base64Visitor { type Value = Vec; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string") } diff --git a/starknet-core/src/serde/num_hex.rs b/starknet-core/src/serde/num_hex.rs index 6268fb1e..f285a18a 100644 --- a/starknet-core/src/serde/num_hex.rs +++ b/starknet-core/src/serde/num_hex.rs @@ -30,7 +30,7 @@ pub mod u64 { impl<'de> Visitor<'de> for NumHexVisitor { type Value = u64; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string, or an array of u8") } diff --git a/starknet-core/src/serde/unsigned_field_element.rs b/starknet-core/src/serde/unsigned_field_element.rs index f443797a..87f311cb 100644 --- a/starknet-core/src/serde/unsigned_field_element.rs +++ b/starknet-core/src/serde/unsigned_field_element.rs @@ -12,10 +12,13 @@ use starknet_types_core::felt::Felt; const PRIME: U256 = U256::from_be_hex("0800000000000011000000000000000000000000000000000000000000000001"); +#[derive(Debug)] pub struct UfeHex; +#[derive(Debug)] pub struct UfeHexOption; +#[derive(Debug)] pub struct UfePendingBlockHash; struct UfeHexVisitor; @@ -51,7 +54,7 @@ impl<'de> DeserializeAs<'de, Felt> for UfeHex { impl<'de> Visitor<'de> for UfeHexVisitor { type Value = Felt; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "a hex string, or an array of u8") } @@ -108,7 +111,7 @@ impl<'de> DeserializeAs<'de, Option> for UfeHexOption { impl<'de> Visitor<'de> for UfeHexOptionVisitor { type Value = Option; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string") } @@ -176,7 +179,7 @@ impl<'de> DeserializeAs<'de, Option> for UfePendingBlockHash { impl<'de> Visitor<'de> for UfePendingBlockHashVisitor { type Value = Option; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string") } diff --git a/starknet-core/src/types/codegen.rs b/starknet-core/src/types/codegen.rs index 46e11560..2d7e0d02 100644 --- a/starknet-core/src/types/codegen.rs +++ b/starknet-core/src/types/codegen.rs @@ -3,7 +3,7 @@ // https://github.com/xJonathanLEI/starknet-jsonrpc-codegen // Code generated with version: -// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen#4118b48cc450a8ff558c2ac480aa12bf5efdd3bd +// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen#fbd3aed2a08d6b29328e87ee0bbfb7e80f7051b0 // These types are ignored from code generation. Implement them manually: // - `RECEIPT_BLOCK` @@ -24,6 +24,9 @@ // - `TXN` // - `TXN_RECEIPT` +#![allow(clippy::doc_markdown)] +#![allow(clippy::missing_const_for_fn)] + use alloc::{format, string::*, vec::*}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; diff --git a/starknet-core/src/types/contract/legacy.rs b/starknet-core/src/types/contract/legacy.rs index 83294a82..3803a218 100644 --- a/starknet-core/src/types/contract/legacy.rs +++ b/starknet-core/src/types/contract/legacy.rs @@ -361,26 +361,26 @@ impl<'de> Deserialize<'de> for RawLegacyAbiEntry { let temp_value = serde_json::Value::deserialize(deserializer)?; match &temp_value["type"] { serde_json::Value::String(type_str) => match &type_str[..] { - "constructor" => Ok(RawLegacyAbiEntry::Constructor( + "constructor" => Ok(Self::Constructor( RawLegacyConstructor::deserialize(temp_value).map_err(|err| { DeError::custom(format!("invalid constructor variant: {err}")) })?, )), - "function" => Ok(RawLegacyAbiEntry::Function( + "function" => Ok(Self::Function( RawLegacyFunction::deserialize(temp_value).map_err(|err| { DeError::custom(format!("invalid function variant: {err}")) })?, )), - "struct" => Ok(RawLegacyAbiEntry::Struct( + "struct" => Ok(Self::Struct( RawLegacyStruct::deserialize(temp_value) .map_err(|err| DeError::custom(format!("invalid struct variant: {err}")))?, )), - "l1_handler" => Ok(RawLegacyAbiEntry::L1Handler( + "l1_handler" => Ok(Self::L1Handler( RawLegacyL1Handler::deserialize(temp_value).map_err(|err| { DeError::custom(format!("invalid l1_handler variant: {err}")) })?, )), - "event" => Ok(RawLegacyAbiEntry::Event( + "event" => Ok(Self::Event( RawLegacyEvent::deserialize(temp_value) .map_err(|err| DeError::custom(format!("invalid event variant: {err}")))?, )), @@ -402,7 +402,7 @@ impl LegacyContractClass { // Hashes external entry points elements.push({ let mut buffer = Vec::new(); - for entrypoint in self.entry_points_by_type.external.iter() { + for entrypoint in &self.entry_points_by_type.external { buffer.push(entrypoint.selector); buffer.push(entrypoint.offset.into()); } @@ -412,7 +412,7 @@ impl LegacyContractClass { // Hashes L1 handler entry points elements.push({ let mut buffer = Vec::new(); - for entrypoint in self.entry_points_by_type.l1_handler.iter() { + for entrypoint in &self.entry_points_by_type.l1_handler { buffer.push(entrypoint.selector); buffer.push(entrypoint.offset.into()); } @@ -422,7 +422,7 @@ impl LegacyContractClass { // Hashes constructor entry points elements.push({ let mut buffer = Vec::new(); - for entrypoint in self.entry_points_by_type.constructor.iter() { + for entrypoint in &self.entry_points_by_type.constructor { buffer.push(entrypoint.selector); buffer.push(entrypoint.offset.into()); } @@ -853,9 +853,7 @@ mod tests { include_str!( "../../../test-data/contracts/cairo0/artifacts/pre-0.11.0/event_example.txt" ), - ] - .into_iter() - { + ] { serde_json::from_str::(raw_artifact).unwrap(); } } @@ -893,7 +891,6 @@ mod tests { ), ), ] - .into_iter() { let artifact = serde_json::from_str::(raw_artifact).unwrap(); let computed_hash = artifact.class_hash().unwrap(); @@ -938,7 +935,6 @@ mod tests { ), ), ] - .into_iter() { let artifact = serde_json::from_str::(raw_artifact).unwrap(); let computed_hash = artifact.hinted_class_hash().unwrap(); diff --git a/starknet-core/src/types/contract/mod.rs b/starknet-core/src/types/contract/mod.rs index 24046f9b..ba1b17ba 100644 --- a/starknet-core/src/types/contract/mod.rs +++ b/starknet-core/src/types/contract/mod.rs @@ -16,7 +16,7 @@ use crate::{ /// Module containing types related to artifacts of contracts compiled with a Cairo 0.x compiler. pub mod legacy; -/// Cairo string for "CONTRACT_CLASS_V0.1.0" +/// Cairo string for `CONTRACT_CLASS_V0.1.0` const PREFIX_CONTRACT_CLASS_V0_1_0: Felt = Felt::from_raw([ 37302452645455172, 18446734822722598327, @@ -24,7 +24,7 @@ const PREFIX_CONTRACT_CLASS_V0_1_0: Felt = Felt::from_raw([ 5800711240972404213, ]); -/// Cairo string for "COMPILED_CLASS_V1" +/// Cairo string for `COMPILED_CLASS_V1` const PREFIX_COMPILED_CLASS_V1: Felt = Felt::from_raw([ 324306817650036332, 18446744073709549462, @@ -278,7 +278,7 @@ struct BytecodeSegmentedNode { /// Internal structure used for post-Sierra-1.5.0 CASM hash calculation. /// -/// Represents a child of [BytecodeSegmentedNode]. +/// Represents a child of [`BytecodeSegmentedNode`]. struct BytecodeSegment { segment_length: u64, #[allow(unused)] @@ -545,12 +545,12 @@ impl CompiledClass { ) -> Result { let mut hasher = PoseidonHasher::new(); - for entry in entrypoints.iter() { + for entry in entrypoints { hasher.update(entry.selector); hasher.update(entry.offset.into()); let mut builtin_hasher = PoseidonHasher::new(); - for builtin in entry.builtins.iter() { + for builtin in &entry.builtins { builtin_hasher.update(cairo_short_string_to_felt(builtin)?) } @@ -594,7 +594,7 @@ impl CompiledClass { let mut res = Vec::new(); let mut total_len = 0; - for item in bytecode_segment_lengths.iter() { + for item in bytecode_segment_lengths { let visited_pc_before = if !visited_pcs.is_empty() { Some(visited_pcs[visited_pcs.len() - 1]) } else { @@ -666,7 +666,7 @@ impl BytecodeLeaf { impl BytecodeSegmentedNode { fn hash(&self) -> Felt { let mut hasher = PoseidonHasher::new(); - for node in self.segments.iter() { + for node in &self.segments { hasher.update(node.segment_length.into()); hasher.update(node.inner_structure.hash()); } @@ -761,7 +761,7 @@ impl Serialize for TypedAbiEvent { } match self { - TypedAbiEvent::Struct(inner) => StructRef::serialize( + Self::Struct(inner) => StructRef::serialize( &StructRef { name: &inner.name, kind: "struct", @@ -769,7 +769,7 @@ impl Serialize for TypedAbiEvent { }, serializer, ), - TypedAbiEvent::Enum(inner) => EnumRef::serialize( + Self::Enum(inner) => EnumRef::serialize( &EnumRef { name: &inner.name, kind: "enum", @@ -790,7 +790,7 @@ impl Serialize for IntOrList { Self::Int(int) => serializer.serialize_u64(*int), Self::List(list) => { let mut seq = serializer.serialize_seq(Some(list.len()))?; - for item in list.iter() { + for item in list { seq.serialize_element(item)?; } seq.end() @@ -802,7 +802,7 @@ impl Serialize for IntOrList { impl<'de> Visitor<'de> for IntOrListVisitor { type Value = IntOrList; - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(formatter, "number or list") } @@ -837,7 +837,7 @@ impl<'de> Deserialize<'de> for IntOrList { fn hash_sierra_entrypoints(entrypoints: &[SierraEntryPoint]) -> Felt { let mut hasher = PoseidonHasher::new(); - for entry in entrypoints.iter() { + for entry in entrypoints { hasher.update(entry.selector); hasher.update(entry.function_idx.into()); } @@ -864,9 +864,7 @@ mod tests { include_str!("../../../test-data/contracts/cairo2/artifacts/abi_types_sierra.txt"), include_str!("../../../test-data/contracts/cairo2/artifacts/erc20_sierra.txt"), include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_sierra.txt"), - ] - .into_iter() - { + ] { match serde_json::from_str::(raw_artifact) { Ok(ContractArtifact::SierraClass(_)) => {} _ => panic!("Unexpected result"), @@ -883,9 +881,7 @@ mod tests { include_str!("../../../test-data/contracts/cairo2/artifacts/abi_types_compiled.txt"), include_str!("../../../test-data/contracts/cairo2/artifacts/erc20_compiled.txt"), include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_compiled.txt"), - ] - .into_iter() - { + ] { match serde_json::from_str::(raw_artifact) { Ok(ContractArtifact::CompiledClass(_)) => {} _ => panic!("Unexpected result"), @@ -924,9 +920,7 @@ mod tests { include_str!("../../../test-data/contracts/cairo2/artifacts/abi_types_sierra.txt"), include_str!("../../../test-data/contracts/cairo2/artifacts/abi_types.hashes.json"), ), - ] - .into_iter() - { + ] { let sierra_class = serde_json::from_str::(raw_artifact).unwrap(); let computed_hash = sierra_class.class_hash().unwrap(); @@ -965,9 +959,7 @@ mod tests { include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_compiled.txt"), include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20.hashes.json"), ), - ] - .into_iter() - { + ] { let compiled_class = serde_json::from_str::(raw_artifact).unwrap(); let computed_hash = compiled_class.class_hash().unwrap(); diff --git a/starknet-core/src/types/conversions.rs b/starknet-core/src/types/conversions.rs index 38e7aa5f..a4a9ba1d 100644 --- a/starknet-core/src/types/conversions.rs +++ b/starknet-core/src/types/conversions.rs @@ -10,33 +10,29 @@ impl From for RawLegacyAbiEntry { fn from(value: LegacyContractAbiEntry) -> Self { match value { LegacyContractAbiEntry::Function(inner) => match inner.r#type { - LegacyFunctionAbiType::Function => RawLegacyAbiEntry::Function(RawLegacyFunction { + LegacyFunctionAbiType::Function => Self::Function(RawLegacyFunction { inputs: inner.inputs, name: inner.name, outputs: inner.outputs, state_mutability: inner.state_mutability, }), - LegacyFunctionAbiType::L1Handler => { - RawLegacyAbiEntry::L1Handler(RawLegacyL1Handler { - inputs: inner.inputs, - name: inner.name, - outputs: inner.outputs, - }) - } - LegacyFunctionAbiType::Constructor => { - RawLegacyAbiEntry::Constructor(RawLegacyConstructor { - inputs: inner.inputs, - name: inner.name, - outputs: inner.outputs, - }) - } + LegacyFunctionAbiType::L1Handler => Self::L1Handler(RawLegacyL1Handler { + inputs: inner.inputs, + name: inner.name, + outputs: inner.outputs, + }), + LegacyFunctionAbiType::Constructor => Self::Constructor(RawLegacyConstructor { + inputs: inner.inputs, + name: inner.name, + outputs: inner.outputs, + }), }, - LegacyContractAbiEntry::Event(inner) => RawLegacyAbiEntry::Event(RawLegacyEvent { + LegacyContractAbiEntry::Event(inner) => Self::Event(RawLegacyEvent { data: inner.data, keys: inner.keys, name: inner.name, }), - LegacyContractAbiEntry::Struct(inner) => RawLegacyAbiEntry::Struct(RawLegacyStruct { + LegacyContractAbiEntry::Struct(inner) => Self::Struct(RawLegacyStruct { members: inner .members .into_iter() diff --git a/starknet-core/src/types/eth_address.rs b/starknet-core/src/types/eth_address.rs index dfc3028e..5bfa95bd 100644 --- a/starknet-core/src/types/eth_address.rs +++ b/starknet-core/src/types/eth_address.rs @@ -83,7 +83,7 @@ impl EthAddress { felt.try_into() } - pub fn as_bytes(&self) -> &[u8; 20] { + pub const fn as_bytes(&self) -> &[u8; 20] { &self.inner } } @@ -109,7 +109,7 @@ impl<'de> Deserialize<'de> for EthAddress { impl<'de> Visitor<'de> for EthAddressVisitor { type Value = EthAddress; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string") } @@ -169,7 +169,7 @@ impl TryFrom<&Felt> for EthAddress { impl From for Felt { fn from(value: EthAddress) -> Self { // Safe to unwrap here as the value is never out of range - Felt::from_bytes_be_slice(&value.inner) + Self::from_bytes_be_slice(&value.inner) } } diff --git a/starknet-core/src/types/execution_result.rs b/starknet-core/src/types/execution_result.rs index 2a757531..b0d56a1c 100644 --- a/starknet-core/src/types/execution_result.rs +++ b/starknet-core/src/types/execution_result.rs @@ -12,10 +12,10 @@ pub enum ExecutionResult { } impl ExecutionResult { - pub fn status(&self) -> TransactionExecutionStatus { + pub const fn status(&self) -> TransactionExecutionStatus { match self { - ExecutionResult::Succeeded => TransactionExecutionStatus::Succeeded, - ExecutionResult::Reverted { .. } => TransactionExecutionStatus::Reverted, + Self::Succeeded => TransactionExecutionStatus::Succeeded, + Self::Reverted { .. } => TransactionExecutionStatus::Reverted, } } @@ -25,8 +25,8 @@ impl ExecutionResult { /// variant. pub fn revert_reason(&self) -> Option<&str> { match self { - ExecutionResult::Succeeded => None, - ExecutionResult::Reverted { reason } => Some(reason), + Self::Succeeded => None, + Self::Reverted { reason } => Some(reason), } } } diff --git a/starknet-core/src/types/hash_256.rs b/starknet-core/src/types/hash_256.rs index ec0bb839..b6ad9061 100644 --- a/starknet-core/src/types/hash_256.rs +++ b/starknet-core/src/types/hash_256.rs @@ -68,7 +68,7 @@ impl Hash256 { felt.into() } - pub fn as_bytes(&self) -> &[u8; HASH_256_BYTE_COUNT] { + pub const fn as_bytes(&self) -> &[u8; HASH_256_BYTE_COUNT] { &self.inner } } @@ -102,7 +102,7 @@ impl<'de> Deserialize<'de> for Hash256 { impl<'de> Visitor<'de> for Hash256Visitor { type Value = Hash256; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string, or an array of u8") } @@ -186,7 +186,7 @@ impl TryFrom<&Hash256> for Felt { type Error = ToFieldElementError; fn try_from(value: &Hash256) -> Result { - Ok(Felt::from_bytes_be(&value.inner)) + Ok(Self::from_bytes_be(&value.inner)) } } @@ -212,7 +212,7 @@ mod tests { "25c5b1592b1743b62d7fabd4373d98219c2ff3750f49ec0608a8355fa3bb060f5", ]; - for item in test_data.into_iter() { + for item in test_data { match Hash256::from_hex(item) { Err(FromHexError::UnexpectedLength) => {} _ => panic!("Unexpected test result"), @@ -230,7 +230,7 @@ mod tests { "0x?5c5b1592b1743b62d7fabd4373d98219c2f63750f49ec0608a8355fa3bb060", ]; - for item in test_data.into_iter() { + for item in test_data { match Hash256::from_hex(item) { Err(FromHexError::InvalidHexString) => {} _ => panic!("Unexpected test result"), diff --git a/starknet-core/src/types/mod.rs b/starknet-core/src/types/mod.rs index 16614753..0d5321f8 100644 --- a/starknet-core/src/types/mod.rs +++ b/starknet-core/src/types/mod.rs @@ -336,7 +336,7 @@ pub enum ExecuteInvocation { mod errors { use core::fmt::{Display, Formatter, Result}; - #[derive(Debug, PartialEq)] + #[derive(Debug, PartialEq, Eq)] pub enum ParseMsgToL2Error { EmptyCalldata, FromAddressOutOfRange, @@ -366,15 +366,15 @@ pub use errors::ParseMsgToL2Error; impl MaybePendingBlockWithTxHashes { pub fn transactions(&self) -> &[Felt] { match self { - MaybePendingBlockWithTxHashes::Block(block) => &block.transactions, - MaybePendingBlockWithTxHashes::PendingBlock(block) => &block.transactions, + Self::Block(block) => &block.transactions, + Self::PendingBlock(block) => &block.transactions, } } - pub fn l1_gas_price(&self) -> &ResourcePrice { + pub const fn l1_gas_price(&self) -> &ResourcePrice { match self { - MaybePendingBlockWithTxHashes::Block(block) => &block.l1_gas_price, - MaybePendingBlockWithTxHashes::PendingBlock(block) => &block.l1_gas_price, + Self::Block(block) => &block.l1_gas_price, + Self::PendingBlock(block) => &block.l1_gas_price, } } } @@ -382,15 +382,15 @@ impl MaybePendingBlockWithTxHashes { impl MaybePendingBlockWithTxs { pub fn transactions(&self) -> &[Transaction] { match self { - MaybePendingBlockWithTxs::Block(block) => &block.transactions, - MaybePendingBlockWithTxs::PendingBlock(block) => &block.transactions, + Self::Block(block) => &block.transactions, + Self::PendingBlock(block) => &block.transactions, } } - pub fn l1_gas_price(&self) -> &ResourcePrice { + pub const fn l1_gas_price(&self) -> &ResourcePrice { match self { - MaybePendingBlockWithTxs::Block(block) => &block.l1_gas_price, - MaybePendingBlockWithTxs::PendingBlock(block) => &block.l1_gas_price, + Self::Block(block) => &block.l1_gas_price, + Self::PendingBlock(block) => &block.l1_gas_price, } } } @@ -398,100 +398,100 @@ impl MaybePendingBlockWithTxs { impl MaybePendingBlockWithReceipts { pub fn transactions(&self) -> &[TransactionWithReceipt] { match self { - MaybePendingBlockWithReceipts::Block(block) => &block.transactions, - MaybePendingBlockWithReceipts::PendingBlock(block) => &block.transactions, + Self::Block(block) => &block.transactions, + Self::PendingBlock(block) => &block.transactions, } } - pub fn l1_gas_price(&self) -> &ResourcePrice { + pub const fn l1_gas_price(&self) -> &ResourcePrice { match self { - MaybePendingBlockWithReceipts::Block(block) => &block.l1_gas_price, - MaybePendingBlockWithReceipts::PendingBlock(block) => &block.l1_gas_price, + Self::Block(block) => &block.l1_gas_price, + Self::PendingBlock(block) => &block.l1_gas_price, } } } impl TransactionStatus { - pub fn finality_status(&self) -> SequencerTransactionStatus { + pub const fn finality_status(&self) -> SequencerTransactionStatus { match self { - TransactionStatus::Received => SequencerTransactionStatus::Received, - TransactionStatus::Rejected => SequencerTransactionStatus::Rejected, - TransactionStatus::AcceptedOnL2(_) => SequencerTransactionStatus::AcceptedOnL2, - TransactionStatus::AcceptedOnL1(_) => SequencerTransactionStatus::AcceptedOnL1, + Self::Received => SequencerTransactionStatus::Received, + Self::Rejected => SequencerTransactionStatus::Rejected, + Self::AcceptedOnL2(_) => SequencerTransactionStatus::AcceptedOnL2, + Self::AcceptedOnL1(_) => SequencerTransactionStatus::AcceptedOnL1, } } } impl Transaction { - pub fn transaction_hash(&self) -> &Felt { + pub const fn transaction_hash(&self) -> &Felt { match self { - Transaction::Invoke(tx) => tx.transaction_hash(), - Transaction::L1Handler(tx) => &tx.transaction_hash, - Transaction::Declare(tx) => tx.transaction_hash(), - Transaction::Deploy(tx) => &tx.transaction_hash, - Transaction::DeployAccount(tx) => tx.transaction_hash(), + Self::Invoke(tx) => tx.transaction_hash(), + Self::L1Handler(tx) => &tx.transaction_hash, + Self::Declare(tx) => tx.transaction_hash(), + Self::Deploy(tx) => &tx.transaction_hash, + Self::DeployAccount(tx) => tx.transaction_hash(), } } } impl InvokeTransaction { - pub fn transaction_hash(&self) -> &Felt { + pub const fn transaction_hash(&self) -> &Felt { match self { - InvokeTransaction::V0(tx) => &tx.transaction_hash, - InvokeTransaction::V1(tx) => &tx.transaction_hash, - InvokeTransaction::V3(tx) => &tx.transaction_hash, + Self::V0(tx) => &tx.transaction_hash, + Self::V1(tx) => &tx.transaction_hash, + Self::V3(tx) => &tx.transaction_hash, } } } impl DeclareTransaction { - pub fn transaction_hash(&self) -> &Felt { + pub const fn transaction_hash(&self) -> &Felt { match self { - DeclareTransaction::V0(tx) => &tx.transaction_hash, - DeclareTransaction::V1(tx) => &tx.transaction_hash, - DeclareTransaction::V2(tx) => &tx.transaction_hash, - DeclareTransaction::V3(tx) => &tx.transaction_hash, + Self::V0(tx) => &tx.transaction_hash, + Self::V1(tx) => &tx.transaction_hash, + Self::V2(tx) => &tx.transaction_hash, + Self::V3(tx) => &tx.transaction_hash, } } } impl DeployAccountTransaction { - pub fn transaction_hash(&self) -> &Felt { + pub const fn transaction_hash(&self) -> &Felt { match self { - DeployAccountTransaction::V1(tx) => &tx.transaction_hash, - DeployAccountTransaction::V3(tx) => &tx.transaction_hash, + Self::V1(tx) => &tx.transaction_hash, + Self::V3(tx) => &tx.transaction_hash, } } } impl TransactionReceipt { - pub fn transaction_hash(&self) -> &Felt { + pub const fn transaction_hash(&self) -> &Felt { match self { - TransactionReceipt::Invoke(receipt) => &receipt.transaction_hash, - TransactionReceipt::L1Handler(receipt) => &receipt.transaction_hash, - TransactionReceipt::Declare(receipt) => &receipt.transaction_hash, - TransactionReceipt::Deploy(receipt) => &receipt.transaction_hash, - TransactionReceipt::DeployAccount(receipt) => &receipt.transaction_hash, + Self::Invoke(receipt) => &receipt.transaction_hash, + Self::L1Handler(receipt) => &receipt.transaction_hash, + Self::Declare(receipt) => &receipt.transaction_hash, + Self::Deploy(receipt) => &receipt.transaction_hash, + Self::DeployAccount(receipt) => &receipt.transaction_hash, } } - pub fn finality_status(&self) -> &TransactionFinalityStatus { + pub const fn finality_status(&self) -> &TransactionFinalityStatus { match self { - TransactionReceipt::Invoke(receipt) => &receipt.finality_status, - TransactionReceipt::L1Handler(receipt) => &receipt.finality_status, - TransactionReceipt::Declare(receipt) => &receipt.finality_status, - TransactionReceipt::Deploy(receipt) => &receipt.finality_status, - TransactionReceipt::DeployAccount(receipt) => &receipt.finality_status, + Self::Invoke(receipt) => &receipt.finality_status, + Self::L1Handler(receipt) => &receipt.finality_status, + Self::Declare(receipt) => &receipt.finality_status, + Self::Deploy(receipt) => &receipt.finality_status, + Self::DeployAccount(receipt) => &receipt.finality_status, } } - pub fn execution_result(&self) -> &ExecutionResult { + pub const fn execution_result(&self) -> &ExecutionResult { match self { - TransactionReceipt::Invoke(receipt) => &receipt.execution_result, - TransactionReceipt::L1Handler(receipt) => &receipt.execution_result, - TransactionReceipt::Declare(receipt) => &receipt.execution_result, - TransactionReceipt::Deploy(receipt) => &receipt.execution_result, - TransactionReceipt::DeployAccount(receipt) => &receipt.execution_result, + Self::Invoke(receipt) => &receipt.execution_result, + Self::L1Handler(receipt) => &receipt.execution_result, + Self::Declare(receipt) => &receipt.execution_result, + Self::Deploy(receipt) => &receipt.execution_result, + Self::DeployAccount(receipt) => &receipt.execution_result, } } } @@ -515,44 +515,44 @@ impl L1HandlerTransaction { } } -impl AsRef for BlockId { - fn as_ref(&self) -> &BlockId { +impl AsRef for BlockId { + fn as_ref(&self) -> &Self { self } } -impl AsRef for FunctionCall { - fn as_ref(&self) -> &FunctionCall { +impl AsRef for FunctionCall { + fn as_ref(&self) -> &Self { self } } -impl AsRef for MsgFromL1 { - fn as_ref(&self) -> &MsgFromL1 { +impl AsRef for MsgFromL1 { + fn as_ref(&self) -> &Self { self } } -impl AsRef for BroadcastedTransaction { - fn as_ref(&self) -> &BroadcastedTransaction { +impl AsRef for BroadcastedTransaction { + fn as_ref(&self) -> &Self { self } } -impl AsRef for BroadcastedInvokeTransaction { - fn as_ref(&self) -> &BroadcastedInvokeTransaction { +impl AsRef for BroadcastedInvokeTransaction { + fn as_ref(&self) -> &Self { self } } -impl AsRef for BroadcastedDeclareTransaction { - fn as_ref(&self) -> &BroadcastedDeclareTransaction { +impl AsRef for BroadcastedDeclareTransaction { + fn as_ref(&self) -> &Self { self } } -impl AsRef for BroadcastedDeployAccountTransaction { - fn as_ref(&self) -> &BroadcastedDeployAccountTransaction { +impl AsRef for BroadcastedDeployAccountTransaction { + fn as_ref(&self) -> &Self { self } } diff --git a/starknet-core/src/types/msg.rs b/starknet-core/src/types/msg.rs index e1f1ce04..c34919e9 100644 --- a/starknet-core/src/types/msg.rs +++ b/starknet-core/src/types/msg.rs @@ -17,7 +17,7 @@ pub struct MsgToL2 { impl MsgToL2 { /// Calculates the message hash based on the algorithm documented here: /// - /// https://docs.starknet.io/documentation/architecture_and_concepts/L1-L2_Communication/messaging-mechanism/ + /// pub fn hash(&self) -> Hash256 { let mut hasher = Keccak256::new(); @@ -40,7 +40,7 @@ impl MsgToL2 { hasher.update((self.payload.len() as u64).to_be_bytes()); // Payload - for item in self.payload.iter() { + for item in &self.payload { hasher.update(item.to_bytes_be()); } @@ -54,7 +54,7 @@ impl MsgToL2 { impl MsgToL1 { /// Calculates the message hash based on the algorithm documented here: /// - /// https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/messaging-mechanism/#structure_and_hashing_l2-l1 + /// pub fn hash(&self) -> Hash256 { let mut hasher = Keccak256::new(); @@ -69,7 +69,7 @@ impl MsgToL1 { hasher.update((self.payload.len() as u64).to_be_bytes()); // Payload - for item in self.payload.iter() { + for item in &self.payload { hasher.update(item.to_bytes_be()); } diff --git a/starknet-core/src/types/receipt_block.rs b/starknet-core/src/types/receipt_block.rs index 5c73d03d..a6216dfe 100644 --- a/starknet-core/src/types/receipt_block.rs +++ b/starknet-core/src/types/receipt_block.rs @@ -13,38 +13,38 @@ pub enum ReceiptBlock { impl ReceiptBlock { /// Returns `true` if and only if it's the `Pending` variant. - pub fn is_pending(&self) -> bool { + pub const fn is_pending(&self) -> bool { match self { - ReceiptBlock::Pending => true, - ReceiptBlock::Block { .. } => false, + Self::Pending => true, + Self::Block { .. } => false, } } /// Returns `true` if and only if it's the `Block` variant. - pub fn is_block(&self) -> bool { + pub const fn is_block(&self) -> bool { match self { - ReceiptBlock::Pending => false, - ReceiptBlock::Block { .. } => true, + Self::Pending => false, + Self::Block { .. } => true, } } /// Returns `None` if block is not `Block`. /// /// A more idiomatic way of accessing the block hash is to match the `Block` enum variant. - pub fn block_hash(&self) -> Option { + pub const fn block_hash(&self) -> Option { match self { - ReceiptBlock::Pending => None, - ReceiptBlock::Block { block_hash, .. } => Some(*block_hash), + Self::Pending => None, + Self::Block { block_hash, .. } => Some(*block_hash), } } /// Returns `None` if block is not `Block`. /// /// A more idiomatic way of accessing the block number is to match the `Block` enum variant. - pub fn block_number(&self) -> Option { + pub const fn block_number(&self) -> Option { match self { - ReceiptBlock::Pending => None, - ReceiptBlock::Block { block_number, .. } => Some(*block_number), + Self::Pending => None, + Self::Block { block_number, .. } => Some(*block_number), } } } diff --git a/starknet-core/src/types/serde_impls.rs b/starknet-core/src/types/serde_impls.rs index 95a5221f..925321c8 100644 --- a/starknet-core/src/types/serde_impls.rs +++ b/starknet-core/src/types/serde_impls.rs @@ -58,7 +58,7 @@ impl<'de> DeserializeAs<'de, u128> for NumAsHex { impl<'de> Visitor<'de> for NumAsHexVisitorU64 { type Value = u64; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string or number") } @@ -98,7 +98,7 @@ impl<'de> Visitor<'de> for NumAsHexVisitorU64 { impl<'de> Visitor<'de> for NumAsHexVisitorU128 { type Value = u128; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string or number") } @@ -128,8 +128,8 @@ impl Serialize for SyncStatusType { S: serde::Serializer, { match self { - SyncStatusType::NotSyncing => serializer.serialize_bool(false), - SyncStatusType::Syncing(sync_status) => SyncStatus::serialize(sync_status, serializer), + Self::NotSyncing => serializer.serialize_bool(false), + Self::Syncing(sync_status) => SyncStatus::serialize(sync_status, serializer), } } } @@ -145,7 +145,7 @@ impl<'de> Deserialize<'de> for SyncStatusType { false => Ok(Self::NotSyncing), }, - SyncStatusTypeDe::SyncStatus(value) => Ok(SyncStatusType::Syncing(value)), + SyncStatusTypeDe::SyncStatus(value) => Ok(Self::Syncing(value)), } } } @@ -233,19 +233,19 @@ mod transaction_status { S: Serializer, { let raw = match self { - TransactionStatus::Received => Raw { + Self::Received => Raw { finality_status: SequencerTransactionStatus::Received, execution_status: None, }, - TransactionStatus::Rejected => Raw { + Self::Rejected => Raw { finality_status: SequencerTransactionStatus::Rejected, execution_status: None, }, - TransactionStatus::AcceptedOnL2(exe) => Raw { + Self::AcceptedOnL2(exe) => Raw { finality_status: SequencerTransactionStatus::AcceptedOnL2, execution_status: Some(*exe), }, - TransactionStatus::AcceptedOnL1(exe) => Raw { + Self::AcceptedOnL1(exe) => Raw { finality_status: SequencerTransactionStatus::AcceptedOnL1, execution_status: Some(*exe), }, @@ -419,9 +419,7 @@ mod tests { (BlockId::Number(1234), "{\"block_number\":1234}"), (BlockId::Tag(BlockTag::Latest), "\"latest\""), (BlockId::Tag(BlockTag::Pending), "\"pending\""), - ] - .into_iter() - { + ] { assert_eq!(serde_json::to_string(&block_id).unwrap(), json); assert_eq!(serde_json::from_str::(json).unwrap(), block_id); } @@ -434,7 +432,7 @@ mod tests { #[derive(Debug, PartialEq, Eq, Deserialize)] struct Value(#[serde_as(as = "NumAsHex")] u64); - for (num, json) in [(Value(100), "\"0x64\""), (Value(100), "100")].into_iter() { + for (num, json) in [(Value(100), "\"0x64\""), (Value(100), "100")] { assert_eq!(serde_json::from_str::(json).unwrap(), num); } } diff --git a/starknet-core/src/types/u256.rs b/starknet-core/src/types/u256.rs index 7f731e3e..f02b87c0 100644 --- a/starknet-core/src/types/u256.rs +++ b/starknet-core/src/types/u256.rs @@ -12,7 +12,7 @@ pub struct U256(crypto_bigint::U256); impl U256 { #[cfg(target_pointer_width = "64")] - pub fn from_words(low: u128, high: u128) -> Self { + pub const fn from_words(low: u128, high: u128) -> Self { Self(crypto_bigint::U256::from_words([ low as u64, (low >> 64) as u64, @@ -22,7 +22,7 @@ impl U256 { } #[cfg(target_pointer_width = "32")] - pub fn from_words(low: u128, high: u128) -> Self { + pub const fn from_words(low: u128, high: u128) -> Self { Self(crypto_bigint::U256::from_words([ low as u32, (low >> 32) as u32, @@ -35,83 +35,83 @@ impl U256 { ])) } - pub fn low(&self) -> u128 { + pub const fn low(&self) -> u128 { let words = u256_to_u64_array(&self.0); words[0] as u128 + ((words[1] as u128) << 64) } - pub fn high(&self) -> u128 { + pub const fn high(&self) -> u128 { let words = u256_to_u64_array(&self.0); words[2] as u128 + ((words[3] as u128) << 64) } } -impl core::ops::Add for U256 { - type Output = U256; +impl core::ops::Add for U256 { + type Output = Self; - fn add(self, rhs: U256) -> Self::Output { + fn add(self, rhs: Self) -> Self::Output { Self(self.0.checked_add(&rhs.0).unwrap()) } } -impl core::ops::AddAssign for U256 { - fn add_assign(&mut self, rhs: U256) { +impl core::ops::AddAssign for U256 { + fn add_assign(&mut self, rhs: Self) { self.0 = self.0.checked_add(&rhs.0).unwrap() } } -impl core::ops::Sub for U256 { - type Output = U256; +impl core::ops::Sub for U256 { + type Output = Self; - fn sub(self, rhs: U256) -> Self::Output { + fn sub(self, rhs: Self) -> Self::Output { Self(self.0.checked_sub(&rhs.0).unwrap()) } } -impl core::ops::SubAssign for U256 { - fn sub_assign(&mut self, rhs: U256) { +impl core::ops::SubAssign for U256 { + fn sub_assign(&mut self, rhs: Self) { self.0 = self.0.checked_sub(&rhs.0).unwrap() } } -impl core::ops::Mul for U256 { - type Output = U256; +impl core::ops::Mul for U256 { + type Output = Self; - fn mul(self, rhs: U256) -> Self::Output { + fn mul(self, rhs: Self) -> Self::Output { Self(self.0.checked_mul(&rhs.0).unwrap()) } } -impl core::ops::MulAssign for U256 { - fn mul_assign(&mut self, rhs: U256) { +impl core::ops::MulAssign for U256 { + fn mul_assign(&mut self, rhs: Self) { self.0 = self.0.checked_mul(&rhs.0).unwrap() } } -impl core::ops::Div for U256 { - type Output = U256; +impl core::ops::Div for U256 { + type Output = Self; - fn div(self, rhs: U256) -> Self::Output { + fn div(self, rhs: Self) -> Self::Output { Self(self.0.checked_div(&rhs.0).unwrap()) } } -impl core::ops::DivAssign for U256 { - fn div_assign(&mut self, rhs: U256) { +impl core::ops::DivAssign for U256 { + fn div_assign(&mut self, rhs: Self) { self.0 = self.0.checked_div(&rhs.0).unwrap() } } -impl core::ops::Rem for U256 { - type Output = U256; +impl core::ops::Rem for U256 { + type Output = Self; - fn rem(self, rhs: U256) -> Self::Output { + fn rem(self, rhs: Self) -> Self::Output { Self(self.0.checked_rem(&rhs.0).unwrap()) } } -impl core::ops::RemAssign for U256 { - fn rem_assign(&mut self, rhs: U256) { +impl core::ops::RemAssign for U256 { + fn rem_assign(&mut self, rhs: Self) { self.0 = self.0.checked_rem(&rhs.0).unwrap() } } @@ -253,13 +253,13 @@ impl From for U256 { #[cfg(target_pointer_width = "64")] #[inline] -fn u256_to_u64_array(num: &crypto_bigint::U256) -> [u64; 4] { +const fn u256_to_u64_array(num: &crypto_bigint::U256) -> [u64; 4] { num.to_words() } #[cfg(target_pointer_width = "32")] #[inline] -fn u256_to_u64_array(num: &crypto_bigint::U256) -> [u64; 4] { +const fn u256_to_u64_array(num: &crypto_bigint::U256) -> [u64; 4] { unsafe { core::mem::transmute::<[u32; 8], [u64; 4]>(num.to_words()) } } diff --git a/starknet-core/src/utils.rs b/starknet-core/src/utils.rs index c1fa8273..10bac139 100644 --- a/starknet-core/src/utils.rs +++ b/starknet-core/src/utils.rs @@ -126,7 +126,7 @@ pub fn get_storage_var_address(var_name: &str, args: &[Felt]) -> Result Result Result { if !str.is_ascii() { return Err(CairoShortStringToFeltError::NonAsciiCharacter); @@ -153,7 +153,7 @@ pub fn cairo_short_string_to_felt(str: &str) -> Result Result { if felt == &Felt::ZERO { return Ok(String::new()); @@ -165,7 +165,7 @@ pub fn parse_cairo_short_string(felt: &Felt) -> Result for Signature { #[cfg(feature = "signature-display")] impl core::fmt::Display for Signature { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, "{}{}", @@ -57,7 +57,7 @@ impl core::fmt::Display for Signature { #[cfg(feature = "signature-display")] impl core::fmt::Display for ExtendedSignature { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, "{}{}{:02x}", @@ -278,7 +278,7 @@ mod tests { serde_json::from_str(json_data).expect("Unable to parse the JSON"); // Iterating over each element in the JSON - for (private_key, expected_public_key) in key_map.into_iter() { + for (private_key, expected_public_key) in key_map { let private_key = if private_key.len() % 2 != 0 { format!("0{}", private_key.trim_start_matches("0x")) } else { diff --git a/starknet-crypto/src/lib.rs b/starknet-crypto/src/lib.rs index 16470b64..47b7db8b 100644 --- a/starknet-crypto/src/lib.rs +++ b/starknet-crypto/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![doc = include_str!("../README.md")] +#[allow(unused_extern_crates)] #[cfg(all(not(feature = "std"), any(test, feature = "alloc")))] extern crate alloc; diff --git a/starknet-crypto/src/pedersen_hash.rs b/starknet-crypto/src/pedersen_hash.rs index a59c5345..5080a826 100644 --- a/starknet-crypto/src/pedersen_hash.rs +++ b/starknet-crypto/src/pedersen_hash.rs @@ -37,7 +37,7 @@ mod tests { ), ]; - for (in1, in2, expected_hash) in test_data.into_iter() { + for (in1, in2, expected_hash) in test_data { let in1 = field_element_from_be_hex(in1); let in2 = field_element_from_be_hex(in2); let expected_hash = field_element_from_be_hex(expected_hash); diff --git a/starknet-crypto/src/poseidon_hash.rs b/starknet-crypto/src/poseidon_hash.rs index 4f3db345..ff96efbb 100644 --- a/starknet-crypto/src/poseidon_hash.rs +++ b/starknet-crypto/src/poseidon_hash.rs @@ -8,7 +8,7 @@ poseidon_consts!(); /// A hasher for Starknet Poseidon hash. /// -/// Using this hasher is the same as calling [poseidon_hash_many]. +/// Using this hasher is the same as calling [`poseidon_hash_many`]. #[derive(Debug, Default)] pub struct PoseidonHasher { state: [Felt; 3], @@ -16,7 +16,7 @@ pub struct PoseidonHasher { } impl PoseidonHasher { - /// Creates a new [PoseidonHasher]. + /// Creates a new [`PoseidonHasher`]. pub fn new() -> Self { Self::default() } @@ -61,7 +61,7 @@ pub fn poseidon_hash(x: Felt, y: Felt) -> Felt { state[0] } -/// Computes the Starknet Poseidon hash of a single [Felt]. +/// Computes the Starknet Poseidon hash of a single [`Felt`]. pub fn poseidon_hash_single(x: Felt) -> Felt { let mut state = [x, Felt::ZERO, Felt::ONE]; poseidon_permute_comp(&mut state); @@ -69,9 +69,9 @@ pub fn poseidon_hash_single(x: Felt) -> Felt { state[0] } -/// Computes the Starknet Poseidon hash of an arbitrary number of [Felt]s. +/// Computes the Starknet Poseidon hash of an arbitrary number of [`Felt`]s. /// -/// Using this function is the same as using [PoseidonHasher]. +/// Using this function is the same as using [`PoseidonHasher`]. pub fn poseidon_hash_many<'a, I: IntoIterator>(msgs: I) -> Felt { let mut state = [Felt::ZERO, Felt::ZERO, Felt::ZERO]; let mut iter = msgs.into_iter(); @@ -141,11 +141,10 @@ fn round_comp(state: &mut [Felt; 3], idx: usize, full: bool) { state[2] += POSEIDON_COMP_CONSTS[idx + 2]; state[0] = state[0] * state[0] * state[0]; state[1] = state[1] * state[1] * state[1]; - state[2] = state[2] * state[2] * state[2]; } else { state[2] += POSEIDON_COMP_CONSTS[idx]; - state[2] = state[2] * state[2] * state[2]; } + state[2] = state[2] * state[2] * state[2]; mix(state); } @@ -176,7 +175,7 @@ mod tests { ), ]; - for (x, y, hash) in test_data.into_iter() { + for (x, y, hash) in test_data { assert_eq!(poseidon_hash(x, y), hash); } } @@ -200,7 +199,7 @@ mod tests { ), ]; - for (x, hash) in test_data.into_iter() { + for (x, hash) in test_data { assert_eq!(poseidon_hash_single(x), hash); } } @@ -252,7 +251,7 @@ mod tests { ), ]; - for (input, hash) in test_data.into_iter() { + for (input, hash) in test_data { // Direct function call assert_eq!(poseidon_hash_many(&input), hash); diff --git a/starknet-crypto/src/rfc6979.rs b/starknet-crypto/src/rfc6979.rs index af2897a9..cd7ea7da 100644 --- a/starknet-crypto/src/rfc6979.rs +++ b/starknet-crypto/src/rfc6979.rs @@ -104,9 +104,9 @@ mod tests { } fn test_generate_k_from_json_str(json_str: &'static str) { - let test_vectors: Vec = serde_json::from_str(json_str).unwrap(); + let test_vectors: Vec> = serde_json::from_str(json_str).unwrap(); - for test_vector in test_vectors.iter() { + for test_vector in &test_vectors { let msg_hash = field_element_from_be_hex(test_vector.msg_hash); let priv_key = field_element_from_be_hex(test_vector.priv_key); let seed = field_element_from_be_hex(test_vector.seed); diff --git a/starknet-curve/Cargo.toml b/starknet-curve/Cargo.toml index 83c291ba..7c01748b 100644 --- a/starknet-curve/Cargo.toml +++ b/starknet-curve/Cargo.toml @@ -14,3 +14,6 @@ keywords = ["ethereum", "starknet", "web3", "no_std"] [dependencies] starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve"] } + +[lints] +workspace = true diff --git a/starknet-macros/Cargo.toml b/starknet-macros/Cargo.toml index 82d6471c..e402e0fb 100644 --- a/starknet-macros/Cargo.toml +++ b/starknet-macros/Cargo.toml @@ -22,3 +22,6 @@ syn = "2.0.15" [features] default = [] use_imported_type = [] + +[lints] +workspace = true diff --git a/starknet-macros/src/lib.rs b/starknet-macros/src/lib.rs index ebeebe38..79d1aade 100644 --- a/starknet-macros/src/lib.rs +++ b/starknet-macros/src/lib.rs @@ -121,6 +121,6 @@ fn field_element_path() -> &'static str { } #[cfg(not(feature = "use_imported_type"))] -fn field_element_path() -> &'static str { +const fn field_element_path() -> &'static str { "::starknet::core::types::Felt" } diff --git a/starknet-providers/Cargo.toml b/starknet-providers/Cargo.toml index 48db0b55..15055413 100644 --- a/starknet-providers/Cargo.toml +++ b/starknet-providers/Cargo.toml @@ -39,3 +39,6 @@ default = [] no_unknown_fields = [ "starknet-core/no_unknown_fields" ] + +[lints] +workspace = true diff --git a/starknet-providers/src/any.rs b/starknet-providers/src/any.rs index 7bbd7f13..beff9c47 100644 --- a/starknet-providers/src/any.rs +++ b/starknet-providers/src/any.rs @@ -20,7 +20,7 @@ use crate::{ /// the [Provider] trait itself cannot be Box-ed due to the use of associated type. /// /// A recommended pattern is to make your business logic code (e.g. functions) generic over the -/// [Provider] trait, while using this [AnyProvider] type for bootstrapping your application. +/// [Provider] trait, while using this [`AnyProvider`] type for bootstrapping your application. /// /// NOTE: This type was introduced when [Provider] was not Box-able. It should be reviewed whether /// it's still needed anymore. diff --git a/starknet-providers/src/jsonrpc/mod.rs b/starknet-providers/src/jsonrpc/mod.rs index e57550cc..be9b9571 100644 --- a/starknet-providers/src/jsonrpc/mod.rs +++ b/starknet-providers/src/jsonrpc/mod.rs @@ -155,7 +155,7 @@ pub enum JsonRpcResponse { Error { id: u64, error: JsonRpcError }, } -/// Failures trying to parse a [JsonRpcError] into [StarknetError]. +/// Failures trying to parse a [`JsonRpcError`] into [`StarknetError`]. #[derive(Debug, thiserror::Error)] pub enum JsonRpcErrorConversionError { #[error("unknown error code")] @@ -175,7 +175,7 @@ struct Felt(#[serde_as(as = "UfeHex")] pub FeltPrimitive); struct FeltArray(#[serde_as(as = "Vec")] pub Vec); impl JsonRpcClient { - pub fn new(transport: T) -> Self { + pub const fn new(transport: T) -> Self { Self { transport } } } @@ -884,16 +884,16 @@ impl TryFrom<&JsonRpcError> for StarknetError { fn try_from(value: &JsonRpcError) -> Result { match value.code { - 1 => Ok(StarknetError::FailedToReceiveTransaction), - 20 => Ok(StarknetError::ContractNotFound), - 24 => Ok(StarknetError::BlockNotFound), - 27 => Ok(StarknetError::InvalidTransactionIndex), - 28 => Ok(StarknetError::ClassHashNotFound), - 29 => Ok(StarknetError::TransactionHashNotFound), - 31 => Ok(StarknetError::PageSizeTooBig), - 32 => Ok(StarknetError::NoBlocks), - 33 => Ok(StarknetError::InvalidContinuationToken), - 34 => Ok(StarknetError::TooManyKeysInFilter), + 1 => Ok(Self::FailedToReceiveTransaction), + 20 => Ok(Self::ContractNotFound), + 24 => Ok(Self::BlockNotFound), + 27 => Ok(Self::InvalidTransactionIndex), + 28 => Ok(Self::ClassHashNotFound), + 29 => Ok(Self::TransactionHashNotFound), + 31 => Ok(Self::PageSizeTooBig), + 32 => Ok(Self::NoBlocks), + 33 => Ok(Self::InvalidContinuationToken), + 34 => Ok(Self::TooManyKeysInFilter), 40 => { let data = ContractErrorData::deserialize( value @@ -902,7 +902,7 @@ impl TryFrom<&JsonRpcError> for StarknetError { .ok_or(JsonRpcErrorConversionError::MissingData)?, ) .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; - Ok(StarknetError::ContractError(data)) + Ok(Self::ContractError(data)) } 41 => { let data = TransactionExecutionErrorData::deserialize( @@ -912,12 +912,12 @@ impl TryFrom<&JsonRpcError> for StarknetError { .ok_or(JsonRpcErrorConversionError::MissingData)?, ) .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; - Ok(StarknetError::TransactionExecutionError(data)) + Ok(Self::TransactionExecutionError(data)) } - 51 => Ok(StarknetError::ClassAlreadyDeclared), - 52 => Ok(StarknetError::InvalidTransactionNonce), - 53 => Ok(StarknetError::InsufficientMaxFee), - 54 => Ok(StarknetError::InsufficientAccountBalance), + 51 => Ok(Self::ClassAlreadyDeclared), + 52 => Ok(Self::InvalidTransactionNonce), + 53 => Ok(Self::InsufficientMaxFee), + 54 => Ok(Self::InsufficientAccountBalance), 55 => { let data = String::deserialize( value @@ -926,15 +926,15 @@ impl TryFrom<&JsonRpcError> for StarknetError { .ok_or(JsonRpcErrorConversionError::MissingData)?, ) .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; - Ok(StarknetError::ValidationFailure(data)) + Ok(Self::ValidationFailure(data)) } - 56 => Ok(StarknetError::CompilationFailed), - 57 => Ok(StarknetError::ContractClassSizeIsTooLarge), - 58 => Ok(StarknetError::NonAccount), - 59 => Ok(StarknetError::DuplicateTx), - 60 => Ok(StarknetError::CompiledClassHashMismatch), - 61 => Ok(StarknetError::UnsupportedTxVersion), - 62 => Ok(StarknetError::UnsupportedContractClassVersion), + 56 => Ok(Self::CompilationFailed), + 57 => Ok(Self::ContractClassSizeIsTooLarge), + 58 => Ok(Self::NonAccount), + 59 => Ok(Self::DuplicateTx), + 60 => Ok(Self::CompiledClassHashMismatch), + 61 => Ok(Self::UnsupportedTxVersion), + 62 => Ok(Self::UnsupportedContractClassVersion), 63 => { let data = String::deserialize( value @@ -943,7 +943,7 @@ impl TryFrom<&JsonRpcError> for StarknetError { .ok_or(JsonRpcErrorConversionError::MissingData)?, ) .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; - Ok(StarknetError::UnexpectedError(data)) + Ok(Self::UnexpectedError(data)) } 10 => { let data = NoTraceAvailableErrorData::deserialize( @@ -953,7 +953,7 @@ impl TryFrom<&JsonRpcError> for StarknetError { .ok_or(JsonRpcErrorConversionError::MissingData)?, ) .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; - Ok(StarknetError::NoTraceAvailable(data)) + Ok(Self::NoTraceAvailable(data)) } _ => Err(JsonRpcErrorConversionError::UnknownCode), } diff --git a/starknet-providers/src/jsonrpc/transports/http.rs b/starknet-providers/src/jsonrpc/transports/http.rs index bd54d8b4..f50bb46a 100644 --- a/starknet-providers/src/jsonrpc/transports/http.rs +++ b/starknet-providers/src/jsonrpc/transports/http.rs @@ -40,8 +40,8 @@ impl HttpTransport { } } - /// Consumes the current [HttpTransport] instance and returns a new one with the header - /// appended. Same as calling [add_header]. + /// Consumes the current [`HttpTransport`] instance and returns a new one with the header + /// appended. Same as calling [`add_header`]. pub fn with_header(self, name: String, value: String) -> Self { let mut headers = self.headers; headers.push((name, value)); @@ -88,7 +88,7 @@ impl JsonRpcTransport for HttpTransport { .post(self.url.clone()) .body(request_body) .header("Content-Type", "application/json"); - for (name, value) in self.headers.iter() { + for (name, value) in &self.headers { request = request.header(name, value); } diff --git a/starknet-providers/src/provider.rs b/starknet-providers/src/provider.rs index 0ee4958a..1d0588da 100644 --- a/starknet-providers/src/provider.rs +++ b/starknet-providers/src/provider.rs @@ -302,10 +302,10 @@ pub trait Provider { /// Trait for implementation-specific error type. These errors are irrelevant in most cases, /// assuming that users typically care more about the specifics of RPC errors instead of the -/// underlying transport. Therefore, it makes little sense to bloat [ProviderError] with a generic +/// underlying transport. Therefore, it makes little sense to bloat [`ProviderError`] with a generic /// parameter just for these errors. Instead, they're erased to this trait object. /// -/// This trait is used instead of a plain [std::error::Error] to allow downcasting, in case access +/// This trait is used instead of a plain [`std::error::Error`] to allow downcasting, in case access /// to the specific error type is indeed desired. This is achieved with the `as_any()` method. pub trait ProviderImplError: Error + Debug + Send + Sync { fn as_any(&self) -> &dyn Any; diff --git a/starknet-providers/src/sequencer/mod.rs b/starknet-providers/src/sequencer/mod.rs index 4453a3ed..b12c91e8 100644 --- a/starknet-providers/src/sequencer/mod.rs +++ b/starknet-providers/src/sequencer/mod.rs @@ -37,7 +37,7 @@ pub enum GatewayClientError { /// JSON serialization/deserialization error #[error(transparent)] Serde(SerdeJsonError), - /// Sequencer error responses not parsable into [StarknetError] + /// Sequencer error responses not parsable into [`StarknetError`] #[error(transparent)] SequencerError(SequencerError), /// Method is not supported (only when using as [Provider]) @@ -139,8 +139,8 @@ impl SequencerGatewayProvider { ) } - /// Consumes the current [SequencerGatewayProvider] instance and returns a new one with the - /// header appended. Same as calling [add_header]. + /// Consumes the current [`SequencerGatewayProvider`] instance and returns a new one with the + /// header appended. Same as calling [`add_header`]. pub fn with_header(self, name: String, value: String) -> Self { let mut headers = self.headers; headers.push((name, value)); @@ -194,7 +194,7 @@ impl SequencerGatewayProvider { trace!("Sending GET request to sequencer API ({})", url); let mut request = self.client.get(url); - for (name, value) in self.headers.iter() { + for (name, value) in &self.headers { request = request.header(name, value); } @@ -228,7 +228,7 @@ impl SequencerGatewayProvider { .post(url) .header("Content-Type", "application/json") .body(request_body); - for (name, value) in self.headers.iter() { + for (name, value) in &self.headers { request = request.header(name, value); } @@ -475,29 +475,27 @@ impl From for ProviderError { fn from(value: SequencerError) -> Self { let matching_code = match value.code { ErrorCode::BlockNotFound => Some(StarknetError::BlockNotFound), - ErrorCode::EntryPointNotFoundInContract => None, - ErrorCode::InvalidProgram => None, - ErrorCode::TransactionFailed => { + ErrorCode::EntryPointNotFoundInContract + | ErrorCode::InvalidContractClass + | ErrorCode::DeprecatedEndpoint + | ErrorCode::MalformedRequest + | ErrorCode::InvalidProgram => None, + ErrorCode::TransactionFailed | ErrorCode::ValidateFailure => { Some(StarknetError::ValidationFailure(value.message.clone())) } - ErrorCode::TransactionNotFound => Some(StarknetError::ContractNotFound), - ErrorCode::UninitializedContract => Some(StarknetError::ContractNotFound), - ErrorCode::MalformedRequest => None, + ErrorCode::TransactionNotFound | ErrorCode::UninitializedContract => { + Some(StarknetError::ContractNotFound) + } ErrorCode::UndeclaredClass => Some(StarknetError::ClassHashNotFound), ErrorCode::InvalidTransactionNonce => Some(StarknetError::InvalidTransactionNonce), - ErrorCode::ValidateFailure => { - Some(StarknetError::ValidationFailure(value.message.clone())) - } ErrorCode::ClassAlreadyDeclared => Some(StarknetError::ClassAlreadyDeclared), ErrorCode::CompilationFailed => Some(StarknetError::CompilationFailed), ErrorCode::InvalidCompiledClassHash => Some(StarknetError::CompiledClassHashMismatch), ErrorCode::DuplicatedTransaction => Some(StarknetError::DuplicateTx), - ErrorCode::InvalidContractClass => None, - ErrorCode::DeprecatedEndpoint => None, }; match matching_code { - Some(code) => ProviderError::StarknetError(code), + Some(code) => Self::StarknetError(code), None => GatewayClientError::SequencerError(value).into(), } } @@ -539,10 +537,10 @@ where { let temp_value = serde_json::Value::deserialize(deserializer)?; if let Ok(value) = T::deserialize(&temp_value) { - return Ok(GatewayResponse::Data(value)); + return Ok(Self::Data(value)); } if let Ok(value) = SequencerError::deserialize(&temp_value) { - return Ok(GatewayResponse::SequencerError(value)); + return Ok(Self::SequencerError(value)); } Err(serde::de::Error::custom( "data did not match any variant of enum GatewayResponse", @@ -583,9 +581,7 @@ mod tests { for raw in [ include_str!("../../test-data/raw_gateway_responses/get_class_by_hash/1_cairo_0.txt"), include_str!("../../test-data/raw_gateway_responses/get_class_by_hash/3_cairo_1.txt"), - ] - .into_iter() - { + ] { serde_json::from_str::>(raw).unwrap(); } } diff --git a/starknet-providers/src/sequencer/models/contract.rs b/starknet-providers/src/sequencer/models/contract.rs index 04584d51..0ef6a2e6 100644 --- a/starknet-providers/src/sequencer/models/contract.rs +++ b/starknet-providers/src/sequencer/models/contract.rs @@ -91,7 +91,7 @@ impl CompressedSierraClass { let compressed_program = gzip_encoder.finish().map_err(DecompressProgramError::Io)?; - Ok(CompressedSierraClass { + Ok(Self { sierra_program: compressed_program, contract_class_version: flattened_class.contract_class_version.clone(), entry_points_by_type: flattened_class.entry_points_by_type.clone(), diff --git a/starknet-providers/src/sequencer/models/conversions.rs b/starknet-providers/src/sequencer/models/conversions.rs index 8e2c6efe..6af9f96a 100644 --- a/starknet-providers/src/sequencer/models/conversions.rs +++ b/starknet-providers/src/sequencer/models/conversions.rs @@ -604,8 +604,9 @@ impl TryFrom for core::TransactionFinalityStatus { fn try_from(value: TransactionFinalityStatus) -> Result { match value { - TransactionFinalityStatus::NotReceived => Err(ConversionError), - TransactionFinalityStatus::Received => Err(ConversionError), + TransactionFinalityStatus::NotReceived | TransactionFinalityStatus::Received => { + Err(ConversionError) + } TransactionFinalityStatus::AcceptedOnL2 => Ok(Self::AcceptedOnL2), TransactionFinalityStatus::AcceptedOnL1 => Ok(Self::AcceptedOnL1), } @@ -1209,7 +1210,7 @@ fn convert_execution_result( } } -fn convert_legacy_entry_point( +const fn convert_legacy_entry_point( value: core::LegacyContractEntryPoint, ) -> contract_legacy::RawLegacyEntryPoint { // WARNING: this causes pre-0.11.0 contract declaration to fail due to `offset` issue diff --git a/starknet-providers/src/sequencer/models/serde_impls.rs b/starknet-providers/src/sequencer/models/serde_impls.rs index f54d344f..fda5b8e7 100644 --- a/starknet-providers/src/sequencer/models/serde_impls.rs +++ b/starknet-providers/src/sequencer/models/serde_impls.rs @@ -20,7 +20,7 @@ pub(crate) mod u64_hex { impl<'de> Visitor<'de> for U64HexVisitor { type Value = u64; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "string") } @@ -56,7 +56,7 @@ pub(crate) mod u128_hex { impl<'de> Visitor<'de> for U128HexVisitor { type Value = u128; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "string") } @@ -95,7 +95,7 @@ pub(crate) mod u64_hex_opt { impl<'de> Visitor<'de> for U64HexOptVisitor { type Value = Option; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "null or string") } diff --git a/starknet-providers/src/sequencer/models/transaction.rs b/starknet-providers/src/sequencer/models/transaction.rs index 388ace7d..75aaa0b6 100644 --- a/starknet-providers/src/sequencer/models/transaction.rs +++ b/starknet-providers/src/sequencer/models/transaction.rs @@ -246,13 +246,13 @@ pub enum DataAvailabilityMode { struct DataAvailabilityModeVisitor; impl TransactionType { - pub fn transaction_hash(&self) -> Felt { + pub const fn transaction_hash(&self) -> Felt { match self { - TransactionType::Declare(inner) => inner.transaction_hash, - TransactionType::Deploy(inner) => inner.transaction_hash, - TransactionType::DeployAccount(inner) => inner.transaction_hash, - TransactionType::InvokeFunction(inner) => inner.transaction_hash, - TransactionType::L1Handler(inner) => inner.transaction_hash, + Self::Declare(inner) => inner.transaction_hash, + Self::Deploy(inner) => inner.transaction_hash, + Self::DeployAccount(inner) => inner.transaction_hash, + Self::InvokeFunction(inner) => inner.transaction_hash, + Self::L1Handler(inner) => inner.transaction_hash, } } } @@ -281,7 +281,7 @@ impl<'de> Deserialize<'de> for DataAvailabilityMode { impl<'de> Visitor<'de> for DataAvailabilityModeVisitor { type Value = DataAvailabilityMode; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "integer") } diff --git a/starknet-providers/src/sequencer/provider.rs b/starknet-providers/src/sequencer/provider.rs index b6b44bcd..313cda9c 100644 --- a/starknet-providers/src/sequencer/provider.rs +++ b/starknet-providers/src/sequencer/provider.rs @@ -113,7 +113,10 @@ impl Provider for SequencerGatewayProvider { .await?; // `NotReceived` is not a valid status for JSON-RPC. It's an error. - if let Some(TransactionFinalityStatus::NotReceived) = &status.finality_status { + if matches!( + &status.finality_status, + Some(TransactionFinalityStatus::NotReceived) + ) { return Err(ProviderError::StarknetError( StarknetError::TransactionHashNotFound, )); diff --git a/starknet-providers/tests/jsonrpc.rs b/starknet-providers/tests/jsonrpc.rs index bddd2ab4..dac0910a 100644 --- a/starknet-providers/tests/jsonrpc.rs +++ b/starknet-providers/tests/jsonrpc.rs @@ -18,7 +18,7 @@ use url::Url; fn create_jsonrpc_client() -> JsonRpcClient { let rpc_url = std::env::var("STARKNET_RPC") - .unwrap_or("https://pathfinder.rpc.sepolia.starknet.rs/rpc/v0_7".into()); + .unwrap_or_else(|_| "https://pathfinder.rpc.sepolia.starknet.rs/rpc/v0_7".into()); JsonRpcClient::new(HttpTransport::new(Url::parse(&rpc_url).unwrap())) } diff --git a/starknet-signers/Cargo.toml b/starknet-signers/Cargo.toml index d0515adf..f608b25f 100644 --- a/starknet-signers/Cargo.toml +++ b/starknet-signers/Cargo.toml @@ -39,3 +39,6 @@ wasm-bindgen-test = "0.3.34" default = [] ledger = ["coins-bip32", "coins-ledger", "semver"] + +[lints] +workspace = true diff --git a/starknet-signers/src/key_pair.rs b/starknet-signers/src/key_pair.rs index 31a7cefe..65047f20 100644 --- a/starknet-signers/src/key_pair.rs +++ b/starknet-signers/src/key_pair.rs @@ -47,7 +47,7 @@ impl SigningKey { Self { secret_scalar } } - pub fn from_secret_scalar(secret_scalar: Felt) -> Self { + pub const fn from_secret_scalar(secret_scalar: Felt) -> Self { Self { secret_scalar } } @@ -92,7 +92,7 @@ impl SigningKey { Ok(()) } - pub fn secret_scalar(&self) -> Felt { + pub const fn secret_scalar(&self) -> Felt { self.secret_scalar } @@ -106,11 +106,11 @@ impl SigningKey { } impl VerifyingKey { - pub fn from_scalar(scalar: Felt) -> Self { + pub const fn from_scalar(scalar: Felt) -> Self { Self { scalar } } - pub fn scalar(&self) -> Felt { + pub const fn scalar(&self) -> Felt { self.scalar } From f6d339c6b897fb38c839485608ca2fe374a6275d Mon Sep 17 00:00:00 2001 From: TheVeloper Date: Wed, 17 Jul 2024 09:56:50 +0200 Subject: [PATCH 18/54] feat: replace poseidon impl with type-rs (#630) --- starknet-crypto/src/lib.rs | 4 +- starknet-crypto/src/poseidon_hash.rs | 75 ++++++---------------------- 2 files changed, 15 insertions(+), 64 deletions(-) diff --git a/starknet-crypto/src/lib.rs b/starknet-crypto/src/lib.rs index 47b7db8b..39420783 100644 --- a/starknet-crypto/src/lib.rs +++ b/starknet-crypto/src/lib.rs @@ -20,9 +20,7 @@ pub use starknet_types_core::felt::Felt; pub use pedersen_hash::pedersen_hash; -pub use poseidon_hash::{ - poseidon_hash, poseidon_hash_many, poseidon_hash_single, poseidon_permute_comp, PoseidonHasher, -}; +pub use poseidon_hash::{poseidon_hash, poseidon_hash_many, poseidon_hash_single, PoseidonHasher}; pub use ecdsa::{get_public_key, recover, sign, verify, ExtendedSignature, Signature}; diff --git a/starknet-crypto/src/poseidon_hash.rs b/starknet-crypto/src/poseidon_hash.rs index ff96efbb..18a4d4e9 100644 --- a/starknet-crypto/src/poseidon_hash.rs +++ b/starknet-crypto/src/poseidon_hash.rs @@ -1,10 +1,7 @@ // Code ported from the the implementation from pathfinder here: // https://github.com/eqlabs/pathfinder/blob/00a1a74a90a7b8a7f1d07ac3e616be1cb39cf8f1/crates/stark_poseidon/src/lib.rs -use starknet_crypto_codegen::poseidon_consts; -use starknet_types_core::felt::Felt; - -poseidon_consts!(); +use starknet_types_core::{felt::Felt, hash::Poseidon}; /// A hasher for Starknet Poseidon hash. /// @@ -27,7 +24,7 @@ impl PoseidonHasher { Some(previous_message) => { self.state[0] += previous_message; self.state[1] += msg; - poseidon_permute_comp(&mut self.state); + Poseidon::hades_permutation(&mut self.state); } None => { self.buffer = Some(msg); @@ -47,7 +44,7 @@ impl PoseidonHasher { self.state[0] += Felt::ONE; } } - poseidon_permute_comp(&mut self.state); + Poseidon::hades_permutation(&mut self.state); self.state[0] } @@ -56,7 +53,7 @@ impl PoseidonHasher { /// Computes the Starknet Poseidon hash of x and y. pub fn poseidon_hash(x: Felt, y: Felt) -> Felt { let mut state = [x, y, Felt::TWO]; - poseidon_permute_comp(&mut state); + Poseidon::hades_permutation(&mut state); state[0] } @@ -64,7 +61,7 @@ pub fn poseidon_hash(x: Felt, y: Felt) -> Felt { /// Computes the Starknet Poseidon hash of a single [`Felt`]. pub fn poseidon_hash_single(x: Felt) -> Felt { let mut state = [x, Felt::ZERO, Felt::ONE]; - poseidon_permute_comp(&mut state); + Poseidon::hades_permutation(&mut state); state[0] } @@ -93,63 +90,17 @@ pub fn poseidon_hash_many<'a, I: IntoIterator>(msgs: I) -> Felt } } - poseidon_permute_comp(&mut state); + Poseidon::hades_permutation(&mut state); } - poseidon_permute_comp(&mut state); + Poseidon::hades_permutation(&mut state); state[0] } -/// Poseidon permutation function. -pub fn poseidon_permute_comp(state: &mut [Felt; 3]) { - let mut idx = 0; - - // Full rounds - for _ in 0..(FULL_ROUNDS / 2) { - round_comp(state, idx, true); - idx += 3; - } - - // Partial rounds - for _ in 0..PARTIAL_ROUNDS { - round_comp(state, idx, false); - idx += 1; - } - - // Full rounds - for _ in 0..(FULL_ROUNDS / 2) { - round_comp(state, idx, true); - idx += 3; - } -} - -/// Linear layer for MDS matrix M = ((3,1,1), (1,-1,1), (1,1,2)) -/// Given state vector x, it returns Mx, optimized by precomputing t. -#[inline(always)] -fn mix(state: &mut [Felt; 3]) { - let t = state[0] + state[1] + state[2]; - state[0] = t + state[0].double(); - state[1] = t - state[1].double(); - state[2] = t - Felt::THREE * state[2]; -} - -#[inline] -fn round_comp(state: &mut [Felt; 3], idx: usize, full: bool) { - if full { - state[0] += POSEIDON_COMP_CONSTS[idx]; - state[1] += POSEIDON_COMP_CONSTS[idx + 1]; - state[2] += POSEIDON_COMP_CONSTS[idx + 2]; - state[0] = state[0] * state[0] * state[0]; - state[1] = state[1] * state[1] * state[1]; - } else { - state[2] += POSEIDON_COMP_CONSTS[idx]; - } - state[2] = state[2] * state[2] * state[2]; - mix(state); -} - #[cfg(test)] mod tests { + use starknet_types_core::hash::StarkHash; + use super::*; #[test] @@ -176,7 +127,7 @@ mod tests { ]; for (x, y, hash) in test_data { - assert_eq!(poseidon_hash(x, y), hash); + assert_eq!(Poseidon::hash(&x, &y), hash); } } @@ -200,7 +151,9 @@ mod tests { ]; for (x, hash) in test_data { - assert_eq!(poseidon_hash_single(x), hash); + let mut state = [x, Felt::ZERO, Felt::ONE]; + Poseidon::hades_permutation(&mut state); + assert_eq!(state[0], hash); } } @@ -253,7 +206,7 @@ mod tests { for (input, hash) in test_data { // Direct function call - assert_eq!(poseidon_hash_many(&input), hash); + assert_eq!(Poseidon::hash_array(&input), hash); // With hasher let mut hasher = PoseidonHasher::new(); From 529946206ec4d03ebd68e0c8356294a33c1a01b8 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Fri, 26 Jul 2024 22:47:45 +0800 Subject: [PATCH 19/54] chore: remove unused crate `starknet-crypto-codegen` (#632) --- .github/workflows/build.yml | 1 - Cargo.lock | 10 - Cargo.toml | 1 - starknet-crypto-codegen/Cargo.toml | 24 - starknet-crypto-codegen/README.md | 1 - starknet-crypto-codegen/src/lib.rs | 16 - starknet-crypto-codegen/src/pedersen.rs | 89 ---- starknet-crypto-codegen/src/poseidon/mod.rs | 112 ----- .../src/poseidon/params.rs | 460 ------------------ starknet-crypto/Cargo.toml | 1 - starknet-crypto/src/lib.rs | 1 - starknet-crypto/src/pedersen_points.rs | 3 - 12 files changed, 719 deletions(-) delete mode 100644 starknet-crypto-codegen/Cargo.toml delete mode 100644 starknet-crypto-codegen/README.md delete mode 100644 starknet-crypto-codegen/src/lib.rs delete mode 100644 starknet-crypto-codegen/src/pedersen.rs delete mode 100644 starknet-crypto-codegen/src/poseidon/mod.rs delete mode 100644 starknet-crypto-codegen/src/poseidon/params.rs delete mode 100644 starknet-crypto/src/pedersen_points.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e76c83db..97b38ad8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,6 @@ jobs: matrix: package: - "starknet-curve" - - "starknet-crypto-codegen" - "starknet-crypto" - "starknet-core" - "starknet-providers" diff --git a/Cargo.lock b/Cargo.lock index 913a3aa3..c1e87047 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2105,22 +2105,12 @@ dependencies = [ "serde", "serde_json", "sha2", - "starknet-crypto-codegen", "starknet-curve", "starknet-types-core", "wasm-bindgen-test", "zeroize", ] -[[package]] -name = "starknet-crypto-codegen" -version = "0.4.0" -dependencies = [ - "starknet-curve", - "starknet-types-core", - "syn 2.0.63", -] - [[package]] name = "starknet-curve" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index cb1a68f6..9e09d340 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ members = [ "starknet-accounts", "starknet-macros", "starknet-curve", - "starknet-crypto-codegen", "examples/starknet-wasm", "examples/starknet-cxx/starknet-cxx", ] diff --git a/starknet-crypto-codegen/Cargo.toml b/starknet-crypto-codegen/Cargo.toml deleted file mode 100644 index 391080c7..00000000 --- a/starknet-crypto-codegen/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "starknet-crypto-codegen" -version = "0.4.0" -authors = ["Jonathan LEI "] -license = "MIT OR Apache-2.0" -edition = "2021" -readme = "README.md" -repository = "https://github.com/xJonathanLEI/starknet-rs" -homepage = "https://starknet.rs/" -description = """ -Codegen macros for `starknet-crypto` -""" -keywords = ["ethereum", "starknet", "web3", "no_std"] - -[lib] -proc-macro = true - -[dependencies] -starknet-curve = { version = "0.5.0", path = "../starknet-curve" } -syn = "2.0.55" -starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve"] } - -[lints] -workspace = true diff --git a/starknet-crypto-codegen/README.md b/starknet-crypto-codegen/README.md deleted file mode 100644 index 05fab7eb..00000000 --- a/starknet-crypto-codegen/README.md +++ /dev/null @@ -1 +0,0 @@ -# Codegen macros for `starknet-crypto` diff --git a/starknet-crypto-codegen/src/lib.rs b/starknet-crypto-codegen/src/lib.rs deleted file mode 100644 index 00f4f4ac..00000000 --- a/starknet-crypto-codegen/src/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -use proc_macro::TokenStream; - -mod pedersen; -mod poseidon; - -/// Generates the lookup table for Pedersen hash. -#[proc_macro] -pub fn lookup_table(input: TokenStream) -> TokenStream { - pedersen::lookup_table(input) -} - -/// Generates the constants from Poseidon params. -#[proc_macro] -pub fn poseidon_consts(_input: TokenStream) -> TokenStream { - poseidon::poseidon_consts() -} diff --git a/starknet-crypto-codegen/src/pedersen.rs b/starknet-crypto-codegen/src/pedersen.rs deleted file mode 100644 index ab0cb007..00000000 --- a/starknet-crypto-codegen/src/pedersen.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Code ported from the build.rs script here: -// https://github.com/eqlabs/pathfinder/blob/7f9a6bb0264943f93a633f61fc4e0bc9237f68a0/crates/stark_hash/build.rs - -use std::fmt::Write; - -use proc_macro::TokenStream; -use starknet_curve::curve_params::{PEDERSEN_P0, PEDERSEN_P1, PEDERSEN_P2, PEDERSEN_P3}; -use starknet_types_core::curve::{AffinePoint, ProjectivePoint}; -use syn::{parse_macro_input, LitInt}; - -pub fn lookup_table(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as LitInt); - let bits: u32 = input.base10_parse().expect("invalid bits"); - - let mut output = String::new(); - writeln!(output, "pub const CURVE_CONSTS_BITS: usize = {bits};").unwrap(); - - push_points(&mut output, "P0", PEDERSEN_P0, 248, bits).expect("push_points failed"); - push_points(&mut output, "P1", PEDERSEN_P1, 4, bits).expect("push_points failed"); - push_points(&mut output, "P2", PEDERSEN_P2, 248, bits).expect("push_points failed"); - push_points(&mut output, "P3", PEDERSEN_P3, 4, bits).expect("push_points failed"); - - output.parse().unwrap() -} - -fn push_points( - buf: &mut String, - name: &str, - base: AffinePoint, - max_bits: u32, - bits: u32, -) -> std::fmt::Result { - let full_chunks = max_bits / bits; - let leftover_bits = max_bits % bits; - let table_size_full = (1 << bits) - 1; - let table_size_leftover = (1 << leftover_bits) - 1; - let len = full_chunks * table_size_full + table_size_leftover; - - writeln!( - buf, - "pub const CURVE_CONSTS_{name}: [starknet_types_core::curve::AffinePoint; {len}] = [" - )?; - - let mut bits_left = max_bits; - let mut outer_point = ProjectivePoint::from_affine(base.x(), base.y()).unwrap(); - while bits_left > 0 { - let eat_bits = std::cmp::min(bits_left, bits); - let table_size = (1 << eat_bits) - 1; - - // Loop through each possible bit combination except zero - let mut inner_point = outer_point.clone(); - for _ in 1..(table_size + 1) { - push_point(buf, &inner_point.to_affine().unwrap())?; - inner_point += &outer_point; - } - - // Shift outer point #bits times - bits_left -= eat_bits; - for _i in 0..bits { - outer_point += outer_point.clone(); - } - } - - writeln!(buf, "];")?; - Ok(()) -} - -fn push_point(buf: &mut String, p: &AffinePoint) -> std::fmt::Result { - let x = p.x().to_raw(); - let y = p.y().to_raw(); - writeln!( - buf, - "starknet_types_core::curve::AffinePoint::new_unchecked(" - )?; - writeln!(buf, "starknet_types_core::felt::Felt::from_raw([")?; - writeln!(buf, "{},", x[0])?; - writeln!(buf, "{},", x[1])?; - writeln!(buf, "{},", x[2])?; - writeln!(buf, "{},", x[3])?; - writeln!(buf, "]),")?; - writeln!(buf, "starknet_types_core::felt::Felt::from_raw([")?; - writeln!(buf, "{},", y[0])?; - writeln!(buf, "{},", y[1])?; - writeln!(buf, "{},", y[2])?; - writeln!(buf, "{},", y[3])?; - writeln!(buf, "]),")?; - writeln!(buf, "),")?; - Ok(()) -} diff --git a/starknet-crypto-codegen/src/poseidon/mod.rs b/starknet-crypto-codegen/src/poseidon/mod.rs deleted file mode 100644 index 2a11c2c5..00000000 --- a/starknet-crypto-codegen/src/poseidon/mod.rs +++ /dev/null @@ -1,112 +0,0 @@ -// Code ported from the build.rs script here: -// https://github.com/eqlabs/pathfinder/blob/00a1a74a90a7b8a7f1d07ac3e616be1cb39cf8f1/crates/stark_poseidon/build.rs - -use std::fmt::Write; - -use proc_macro::TokenStream; -use starknet_types_core::felt::Felt; - -mod params; - -const FULL_ROUNDS: usize = 8; -const PARTIAL_ROUNDS: usize = 83; - -pub fn poseidon_consts() -> TokenStream { - let round_keys = params::RAW_ROUND_KEYS - .iter() - .map(|key| key.map(|num| Felt::from_dec_str(num).expect("Invalid round key"))) - .collect::>(); - - let flat = round_keys.iter().flatten().cloned().collect::>(); - let comp = compress_roundkeys(&round_keys); - - let mut buffer = String::new(); - - writeln!(buffer, "const FULL_ROUNDS: usize = {FULL_ROUNDS};").unwrap(); - writeln!(buffer, "const PARTIAL_ROUNDS: usize = {PARTIAL_ROUNDS};").unwrap(); - - writeln!(buffer).unwrap(); - - writeln!(buffer, "{}", generate_code("POSEIDON_CONSTS", &flat)).unwrap(); - writeln!(buffer).unwrap(); - - writeln!(buffer, "{}", generate_code("POSEIDON_COMP_CONSTS", &comp)).unwrap(); - - buffer.parse().expect("Invalid code generated") -} - -pub fn compress_roundkeys(rcs: &[[Felt; 3]]) -> Vec { - let mut result = Vec::new(); - - // Add first full rounds - result.extend(rcs[..FULL_ROUNDS / 2].iter().flatten()); - - // Add compressed partial rounds and first of the last full rounds - result.extend(compress_roundkeys_partial(rcs)); - - // Add last full rounds except the first of them - result.extend( - rcs[(FULL_ROUNDS / 2 + PARTIAL_ROUNDS + 1)..] - .iter() - .flatten(), - ); - - result -} - -pub fn compress_roundkeys_partial(rcs: &[[Felt; 3]]) -> Vec { - let mut result = Vec::new(); - - let mut idx = FULL_ROUNDS / 2; - let mut state: [Felt; 3] = [Felt::ZERO; 3]; - - // Add keys for partial rounds - for _ in 0..PARTIAL_ROUNDS { - // AddRoundKey - state[0] += rcs[idx][0]; - state[1] += rcs[idx][1]; - state[2] += rcs[idx][2]; - - // Add last state - result.push(state[2]); - - // Reset last state - state[2] = Felt::ZERO; - - // MixLayer - let t = state[0] + state[1] + state[2]; - state[0] = t + state[0].double(); - state[1] = t - state[1].double(); - state[2] = t - Felt::THREE * state[2]; - - idx += 1; - } - - // Add keys for first of the last full rounds - state[0] += rcs[idx][0]; - state[1] += rcs[idx][1]; - state[2] += rcs[idx][2]; - result.push(state[0]); - result.push(state[1]); - result.push(state[2]); - - result -} - -pub fn generate_code(name: &str, rcs: &[Felt]) -> String { - let mut buf = String::with_capacity(1024 * 1024); - - writeln!(buf, "pub const {}: [Felt; {}] = [", name, rcs.len()).unwrap(); - - rcs.iter().for_each(|num| { - writeln!( - buf, - "Felt::from_raw([{}]),", - num.to_raw().map(|ele| format!("{ele}")).join(",") - ) - .unwrap(); - }); - - writeln!(buf, "];").unwrap(); - buf -} diff --git a/starknet-crypto-codegen/src/poseidon/params.rs b/starknet-crypto-codegen/src/poseidon/params.rs deleted file mode 100644 index 13d9ec08..00000000 --- a/starknet-crypto-codegen/src/poseidon/params.rs +++ /dev/null @@ -1,460 +0,0 @@ -// Extracted from: -// https://github.com/starkware-industries/poseidon/blob/5403dff9ff4eadb07deb5c0a43e88bedb011deb8/poseidon3.txt - -pub const RAW_ROUND_KEYS: [[&str; 3]; 91] = [ - [ - "2950795762459345168613727575620414179244544320470208355568817838579231751791", - "1587446564224215276866294500450702039420286416111469274423465069420553242820", - "1645965921169490687904413452218868659025437693527479459426157555728339600137", - ], - [ - "2782373324549879794752287702905278018819686065818504085638398966973694145741", - "3409172630025222641379726933524480516420204828329395644967085131392375707302", - "2379053116496905638239090788901387719228422033660130943198035907032739387135", - ], - [ - "2570819397480941104144008784293466051718826502582588529995520356691856497111", - "3546220846133880637977653625763703334841539452343273304410918449202580719746", - "2720682389492889709700489490056111332164748138023159726590726667539759963454", - ], - [ - "1899653471897224903834726250400246354200311275092866725547887381599836519005", - "2369443697923857319844855392163763375394720104106200469525915896159690979559", - "2354174693689535854311272135513626412848402744119855553970180659094265527996", - ], - [ - "2404084503073127963385083467393598147276436640877011103379112521338973185443", - "950320777137731763811524327595514151340412860090489448295239456547370725376", - "2121140748740143694053732746913428481442990369183417228688865837805149503386", - ], - [ - "2372065044800422557577242066480215868569521938346032514014152523102053709709", - "2618497439310693947058545060953893433487994458443568169824149550389484489896", - "3518297267402065742048564133910509847197496119850246255805075095266319996916", - ], - [ - "340529752683340505065238931581518232901634742162506851191464448040657139775", - "1954876811294863748406056845662382214841467408616109501720437541211031966538", - "813813157354633930267029888722341725864333883175521358739311868164460385261", - ], - [ - "71901595776070443337150458310956362034911936706490730914901986556638720031", - "2789761472166115462625363403490399263810962093264318361008954888847594113421", - "2628791615374802560074754031104384456692791616314774034906110098358135152410", - ], - [ - "3617032588734559635167557152518265808024917503198278888820567553943986939719", - "2624012360209966117322788103333497793082705816015202046036057821340914061980", - "149101987103211771991327927827692640556911620408176100290586418839323044234", - ], - [ - "1039927963829140138166373450440320262590862908847727961488297105916489431045", - "2213946951050724449162431068646025833746639391992751674082854766704900195669", - "2792724903541814965769131737117981991997031078369482697195201969174353468597", - ], - [ - "3212031629728871219804596347439383805499808476303618848198208101593976279441", - "3343514080098703935339621028041191631325798327656683100151836206557453199613", - "614054702436541219556958850933730254992710988573177298270089989048553060199", - ], - [ - "148148081026449726283933484730968827750202042869875329032965774667206931170", - "1158283532103191908366672518396366136968613180867652172211392033571980848414", - "1032400527342371389481069504520755916075559110755235773196747439146396688513", - ], - [ - "806900704622005851310078578853499250941978435851598088619290797134710613736", - "462498083559902778091095573017508352472262817904991134671058825705968404510", - "1003580119810278869589347418043095667699674425582646347949349245557449452503", - ], - [ - "619074932220101074089137133998298830285661916867732916607601635248249357793", - "2635090520059500019661864086615522409798872905401305311748231832709078452746", - "978252636251682252755279071140187792306115352460774007308726210405257135181", - ], - [ - "1766912167973123409669091967764158892111310474906691336473559256218048677083", - "1663265127259512472182980890707014969235283233442916350121860684522654120381", - "3532407621206959585000336211742670185380751515636605428496206887841428074250", - ], - [ - "2507023127157093845256722098502856938353143387711652912931112668310034975446", - "3321152907858462102434883844787153373036767230808678981306827073335525034593", - "3039253036806065280643845548147711477270022154459620569428286684179698125661", - ], - [ - "103480338868480851881924519768416587261556021758163719199282794248762465380", - "2394049781357087698434751577708655768465803975478348134669006211289636928495", - "2660531560345476340796109810821127229446538730404600368347902087220064379579", - ], - [ - "3603166934034556203649050570865466556260359798872408576857928196141785055563", - "1553799760191949768532188139643704561532896296986025007089826672890485412324", - "2744284717053657689091306578463476341218866418732695211367062598446038965164", - ], - [ - "320745764922149897598257794663594419839885234101078803811049904310835548856", - "979382242100682161589753881721708883681034024104145498709287731138044566302", - "1860426855810549882740147175136418997351054138609396651615467358416651354991", - ], - [ - "336173081054369235994909356892506146234495707857220254489443629387613956145", - "1632470326779699229772327605759783482411227247311431865655466227711078175883", - "921958250077481394074960433988881176409497663777043304881055317463712938502", - ], - [ - "3034358982193370602048539901033542101022185309652879937418114324899281842797", - "25626282149517463867572353922222474817434101087272320606729439087234878607", - "3002662261401575565838149305485737102400501329139562227180277188790091853682", - ], - [ - "2939684373453383817196521641512509179310654199629514917426341354023324109367", - "1076484609897998179434851570277297233169621096172424141759873688902355505136", - "2575095284833160494841112025725243274091830284746697961080467506739203605049", - ], - [ - "3565075264617591783581665711620369529657840830498005563542124551465195621851", - "2197016502533303822395077038351174326125210255869204501838837289716363437993", - "331415322883530754594261416546036195982886300052707474899691116664327869405", - ], - [ - "1935011233711290003793244296594669823169522055520303479680359990463281661839", - "3495901467168087413996941216661589517270845976538454329511167073314577412322", - "954195417117133246453562983448451025087661597543338750600301835944144520375", - ], - [ - "1271840477709992894995746871435810599280944810893784031132923384456797925777", - "2565310762274337662754531859505158700827688964841878141121196528015826671847", - "3365022288251637014588279139038152521653896670895105540140002607272936852513", - ], - [ - "1660592021628965529963974299647026602622092163312666588591285654477111176051", - "970104372286014048279296575474974982288801187216974504035759997141059513421", - "2617024574317953753849168721871770134225690844968986289121504184985993971227", - ], - [ - "999899815343607746071464113462778273556695659506865124478430189024755832262", - "2228536129413411161615629030408828764980855956560026807518714080003644769896", - "2701953891198001564547196795777701119629537795442025393867364730330476403227", - ], - [ - "837078355588159388741598313782044128527494922918203556465116291436461597853", - "2121749601840466143704862369657561429793951309962582099604848281796392359214", - "771812260179247428733132708063116523892339056677915387749121983038690154755", - ], - [ - "3317336423132806446086732225036532603224267214833263122557471741829060578219", - "481570067997721834712647566896657604857788523050900222145547508314620762046", - "242195042559343964206291740270858862066153636168162642380846129622127460192", - ], - [ - "2855462178889999218204481481614105202770810647859867354506557827319138379686", - "3525521107148375040131784770413887305850308357895464453970651672160034885202", - "1320839531502392535964065058804908871811967681250362364246430459003920305799", - ], - [ - "2514191518588387125173345107242226637171897291221681115249521904869763202419", - "2798335750958827619666318316247381695117827718387653874070218127140615157902", - "2808467767967035643407948058486565877867906577474361783201337540214875566395", - ], - [ - "3551834385992706206273955480294669176699286104229279436819137165202231595747", - "1219439673853113792340300173186247996249367102884530407862469123523013083971", - "761519904537984520554247997444508040636526566551719396202550009393012691157", - ], - [ - "3355402549169351700500518865338783382387571349497391475317206324155237401353", - "199541098009731541347317515995192175813554789571447733944970283654592727138", - "192100490643078165121235261796864975568292640203635147901612231594408079071", - ], - [ - "1187019357602953326192019968809486933768550466167033084944727938441427050581", - "189525349641911362389041124808934468936759383310282010671081989585219065700", - "2831653363992091308880573627558515686245403755586311978724025292003353336665", - ], - [ - "2052859812632218952608271535089179639890275494426396974475479657192657094698", - "1670756178709659908159049531058853320846231785448204274277900022176591811072", - "3538757242013734574731807289786598937548399719866320954894004830207085723125", - ], - [ - "710549042741321081781917034337800036872214466705318638023070812391485261299", - "2345013122330545298606028187653996682275206910242635100920038943391319595180", - "3528369671971445493932880023233332035122954362711876290904323783426765912206", - ], - [ - "1167120829038120978297497195837406760848728897181138760506162680655977700764", - "3073243357129146594530765548901087443775563058893907738967898816092270628884", - "378514724418106317738164464176041649567501099164061863402473942795977719726", - ], - [ - "333391138410406330127594722511180398159664250722328578952158227406762627796", - "1727570175639917398410201375510924114487348765559913502662122372848626931905", - "968312190621809249603425066974405725769739606059422769908547372904403793174", - ], - [ - "360659316299446405855194688051178331671817370423873014757323462844775818348", - "1386580151907705298970465943238806620109618995410132218037375811184684929291", - "3604888328937389309031638299660239238400230206645344173700074923133890528967", - ], - [ - "2496185632263372962152518155651824899299616724241852816983268163379540137546", - "486538168871046887467737983064272608432052269868418721234810979756540672990", - "1558415498960552213241704009433360128041672577274390114589014204605400783336", - ], - [ - "3512058327686147326577190314835092911156317204978509183234511559551181053926", - "2235429387083113882635494090887463486491842634403047716936833563914243946191", - "1290896777143878193192832813769470418518651727840187056683408155503813799882", - ], - [ - "1143310336918357319571079551779316654556781203013096026972411429993634080835", - "3235435208525081966062419599803346573407862428113723170955762956243193422118", - "1293239921425673430660897025143433077974838969258268884994339615096356996604", - ], - [ - "236252269127612784685426260840574970698541177557674806964960352572864382971", - "1733907592497266237374827232200506798207318263912423249709509725341212026275", - "302004309771755665128395814807589350526779835595021835389022325987048089868", - ], - [ - "3018926838139221755384801385583867283206879023218491758435446265703006270945", - "39701437664873825906031098349904330565195980985885489447836580931425171297", - "908381723021746969965674308809436059628307487140174335882627549095646509778", - ], - [ - "219062858908229855064136253265968615354041842047384625689776811853821594358", - "1283129863776453589317845316917890202859466483456216900835390291449830275503", - "418512623547417594896140369190919231877873410935689672661226540908900544012", - ], - [ - "1792181590047131972851015200157890246436013346535432437041535789841136268632", - "370546432987510607338044736824316856592558876687225326692366316978098770516", - "3323437805230586112013581113386626899534419826098235300155664022709435756946", - ], - [ - "910076621742039763058481476739499965761942516177975130656340375573185415877", - "1762188042455633427137702520675816545396284185254002959309669405982213803405", - "2186362253913140345102191078329764107619534641234549431429008219905315900520", - ], - [ - "2230647725927681765419218738218528849146504088716182944327179019215826045083", - "1069243907556644434301190076451112491469636357133398376850435321160857761825", - "2695241469149243992683268025359863087303400907336026926662328156934068747593", - ], - [ - "1361519681544413849831669554199151294308350560528931040264950307931824877035", - "1339116632207878730171031743761550901312154740800549632983325427035029084904", - "790593524918851401449292693473498591068920069246127392274811084156907468875", - ], - [ - "2723400368331924254840192318398326090089058735091724263333980290765736363637", - "3457180265095920471443772463283225391927927225993685928066766687141729456030", - "1483675376954327086153452545475557749815683871577400883707749788555424847954", - ], - [ - "2926303836265506736227240325795090239680154099205721426928300056982414025239", - "543969119775473768170832347411484329362572550684421616624136244239799475526", - "237401230683847084256617415614300816373730178313253487575312839074042461932", - ], - [ - "844568412840391587862072008674263874021460074878949862892685736454654414423", - "151922054871708336050647150237534498235916969120198637893731715254687336644", - "1299332034710622815055321547569101119597030148120309411086203580212105652312", - ], - [ - "487046922649899823989594814663418784068895385009696501386459462815688122993", - "1104883249092599185744249485896585912845784382683240114120846423960548576851", - "1458388705536282069567179348797334876446380557083422364875248475157495514484", - ], - [ - "850248109622750774031817200193861444623975329881731864752464222442574976566", - "2885843173858536690032695698009109793537724845140477446409245651176355435722", - "3027068551635372249579348422266406787688980506275086097330568993357835463816", - ], - [ - "3231892723647447539926175383213338123506134054432701323145045438168976970994", - "1719080830641935421242626784132692936776388194122314954558418655725251172826", - "1172253756541066126131022537343350498482225068791630219494878195815226839450", - ], - [ - "1619232269633026603732619978083169293258272967781186544174521481891163985093", - "3495680684841853175973173610562400042003100419811771341346135531754869014567", - "1576161515913099892951745452471618612307857113799539794680346855318958552758", - ], - [ - "2618326122974253423403350731396350223238201817594761152626832144510903048529", - "2696245132758436974032479782852265185094623165224532063951287925001108567649", - "930116505665110070247395429730201844026054810856263733273443066419816003444", - ], - [ - "2786389174502246248523918824488629229455088716707062764363111940462137404076", - "1555260846425735320214671887347115247546042526197895180675436886484523605116", - "2306241912153325247392671742757902161446877415586158295423293240351799505917", - ], - [ - "411529621724849932999694270803131456243889635467661223241617477462914950626", - "1542495485262286701469125140275904136434075186064076910329015697714211835205", - "1853045663799041100600825096887578544265580718909350942241802897995488264551", - ], - [ - "2963055259497271220202739837493041799968576111953080503132045092194513937286", - "2303806870349915764285872605046527036748108533406243381676768310692344456050", - "2622104986201990620910286730213140904984256464479840856728424375142929278875", - ], - [ - "2369987021925266811581727383184031736927816625797282287927222602539037105864", - "285070227712021899602056480426671736057274017903028992288878116056674401781", - "3034087076179360957800568733595959058628497428787907887933697691951454610691", - ], - [ - "469095854351700119980323115747590868855368701825706298740201488006320881056", - "360001976264385426746283365024817520563236378289230404095383746911725100012", - "3438709327109021347267562000879503009590697221730578667498351600602230296178", - ], - [ - "63573904800572228121671659287593650438456772568903228287754075619928214969", - "3470881855042989871434874691030920672110111605547839662680968354703074556970", - "724559311507950497340993415408274803001166693839947519425501269424891465492", - ], - [ - "880409284677518997550768549487344416321062350742831373397603704465823658986", - "6876255662475867703077362872097208259197756317287339941435193538565586230", - "2701916445133770775447884812906226786217969545216086200932273680400909154638", - ], - [ - "425152119158711585559310064242720816611629181537672850898056934507216982586", - "1475552998258917706756737045704649573088377604240716286977690565239187213744", - "2413772448122400684309006716414417978370152271397082147158000439863002593561", - ], - [ - "392160855822256520519339260245328807036619920858503984710539815951012864164", - "1075036996503791536261050742318169965707018400307026402939804424927087093987", - "2176439430328703902070742432016450246365760303014562857296722712989275658921", - ], - [ - "1413865976587623331051814207977382826721471106513581745229680113383908569693", - "4879283427490523253696177116563427032332223531862961281430108575019551814", - "3392583297537374046875199552977614390492290683707960975137418536812266544902", - ], - [ - "3600854486849487646325182927019642276644093512133907046667282144129939150983", - "2779924664161372134024229593301361846129279572186444474616319283535189797834", - "2722699960903170449291146429799738181514821447014433304730310678334403972040", - ], - [ - "819109815049226540285781191874507704729062681836086010078910930707209464699", - "3046121243742768013822760785918001632929744274211027071381357122228091333823", - "1339019590803056172509793134119156250729668216522001157582155155947567682278", - ], - [ - "1933279639657506214789316403763326578443023901555983256955812717638093967201", - "2138221547112520744699126051903811860205771600821672121643894708182292213541", - "2694713515543641924097704224170357995809887124438248292930846280951601597065", - ], - [ - "2471734202930133750093618989223585244499567111661178960753938272334153710615", - "504903761112092757611047718215309856203214372330635774577409639907729993533", - "1943979703748281357156510253941035712048221353507135074336243405478613241290", - ], - [ - "684525210957572142559049112233609445802004614280157992196913315652663518936", - "1705585400798782397786453706717059483604368413512485532079242223503960814508", - "192429517716023021556170942988476050278432319516032402725586427701913624665", - ], - [ - "1586493702243128040549584165333371192888583026298039652930372758731750166765", - "686072673323546915014972146032384917012218151266600268450347114036285993377", - "3464340397998075738891129996710075228740496767934137465519455338004332839215", - ], - [ - "2805249176617071054530589390406083958753103601524808155663551392362371834663", - "667746464250968521164727418691487653339733392025160477655836902744186489526", - "1131527712905109997177270289411406385352032457456054589588342450404257139778", - ], - [ - "1908969485750011212309284349900149072003218505891252313183123635318886241171", - "1025257076985551890132050019084873267454083056307650830147063480409707787695", - "2153175291918371429502545470578981828372846236838301412119329786849737957977", - ], - [ - "3410257749736714576487217882785226905621212230027780855361670645857085424384", - "3442969106887588154491488961893254739289120695377621434680934888062399029952", - "3029953900235731770255937704976720759948880815387104275525268727341390470237", - ], - [ - "85453456084781138713939104192561924536933417707871501802199311333127894466", - "2730629666577257820220329078741301754580009106438115341296453318350676425129", - "178242450661072967256438102630920745430303027840919213764087927763335940415", - ], - [ - "2844589222514708695700541363167856718216388819406388706818431442998498677557", - "3547876269219141094308889387292091231377253967587961309624916269569559952944", - "2525005406762984211707203144785482908331876505006839217175334833739957826850", - ], - [ - "3096397013555211396701910432830904669391580557191845136003938801598654871345", - "574424067119200181933992948252007230348512600107123873197603373898923821490", - "1714030696055067278349157346067719307863507310709155690164546226450579547098", - ], - [ - "2339895272202694698739231405357972261413383527237194045718815176814132612501", - "3562501318971895161271663840954705079797767042115717360959659475564651685069", - "69069358687197963617161747606993436483967992689488259107924379545671193749", - ], - [ - "2614502738369008850475068874731531583863538486212691941619835266611116051561", - "655247349763023251625727726218660142895322325659927266813592114640858573566", - "2305235672527595714255517865498269719545193172975330668070873705108690670678", - ], - [ - "926416070297755413261159098243058134401665060349723804040714357642180531931", - "866523735635840246543516964237513287099659681479228450791071595433217821460", - "2284334068466681424919271582037156124891004191915573957556691163266198707693", - ], - [ - "1812588309302477291425732810913354633465435706480768615104211305579383928792", - "2836899808619013605432050476764608707770404125005720004551836441247917488507", - "2989087789022865112405242078196235025698647423649950459911546051695688370523", - ], - [ - "68056284404189102136488263779598243992465747932368669388126367131855404486", - "505425339250887519581119854377342241317528319745596963584548343662758204398", - "2118963546856545068961709089296976921067035227488975882615462246481055679215", - ], - [ - "2253872596319969096156004495313034590996995209785432485705134570745135149681", - "1625090409149943603241183848936692198923183279116014478406452426158572703264", - "179139838844452470348634657368199622305888473747024389514258107503778442495", - ], - [ - "1567067018147735642071130442904093290030432522257811793540290101391210410341", - "2737301854006865242314806979738760349397411136469975337509958305470398783585", - "3002738216460904473515791428798860225499078134627026021350799206894618186256", - ], - [ - "374029488099466837453096950537275565120689146401077127482884887409712315162", - "973403256517481077805460710540468856199855789930951602150773500862180885363", - "2691967457038172130555117632010860984519926022632800605713473799739632878867", - ], - [ - "3515906794910381201365530594248181418811879320679684239326734893975752012109", - "148057579455448384062325089530558091463206199724854022070244924642222283388", - "1541588700238272710315890873051237741033408846596322948443180470429851502842", - ], - [ - "147013865879011936545137344076637170977925826031496203944786839068852795297", - "2630278389304735265620281704608245039972003761509102213752997636382302839857", - "1359048670759642844930007747955701205155822111403150159614453244477853867621", - ], - [ - "2438984569205812336319229336885480537793786558293523767186829418969842616677", - "2137792255841525507649318539501906353254503076308308692873313199435029594138", - "2262318076430740712267739371170174514379142884859595360065535117601097652755", - ], - [ - "2792703718581084537295613508201818489836796608902614779596544185252826291584", - "2294173715793292812015960640392421991604150133581218254866878921346561546149", - "2770011224727997178743274791849308200493823127651418989170761007078565678171", - ], -]; diff --git a/starknet-crypto/Cargo.toml b/starknet-crypto/Cargo.toml index 300f9770..29164d2a 100644 --- a/starknet-crypto/Cargo.toml +++ b/starknet-crypto/Cargo.toml @@ -14,7 +14,6 @@ keywords = ["ethereum", "starknet", "web3", "no_std"] exclude = ["test-data/**"] [dependencies] -starknet-crypto-codegen = { version = "0.4.0", path = "../starknet-crypto-codegen" } starknet-curve = { version = "0.5.0", path = "../starknet-curve" } crypto-bigint = { version = "0.5.1", default-features = false, features = ["generic-array", "zeroize"] } hmac = { version = "0.12.1", default-features = false } diff --git a/starknet-crypto/src/lib.rs b/starknet-crypto/src/lib.rs index 39420783..551141e9 100644 --- a/starknet-crypto/src/lib.rs +++ b/starknet-crypto/src/lib.rs @@ -9,7 +9,6 @@ mod ecdsa; mod error; mod fe_utils; mod pedersen_hash; -mod pedersen_points; mod poseidon_hash; mod rfc6979; diff --git a/starknet-crypto/src/pedersen_points.rs b/starknet-crypto/src/pedersen_points.rs deleted file mode 100644 index 817b1092..00000000 --- a/starknet-crypto/src/pedersen_points.rs +++ /dev/null @@ -1,3 +0,0 @@ -use starknet_crypto_codegen::lookup_table; - -lookup_table!(4); From a9895554ce67ed3547a262728d18aba68451df7a Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Sat, 27 Jul 2024 22:58:51 +0800 Subject: [PATCH 20/54] docs: add docs for `starknet-curve` (#633) --- starknet-curve/README.md | 13 ++++++- starknet-curve/src/curve_params.rs | 54 ++++++++++++++++++++++++++++++ starknet-curve/src/lib.rs | 5 ++- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/starknet-curve/README.md b/starknet-curve/README.md index 09e089dd..27300e0c 100644 --- a/starknet-curve/README.md +++ b/starknet-curve/README.md @@ -1 +1,12 @@ -# Starknet Curve +# Starknet Curve Parameters + +The `starknet-curve` crate contains a few useful parameters for the STARK curve defined as: + +``` +y^2 = x^3 + alpha * x + beta +``` + +where: + +- `alpha` = `0x0000000000000000000000000000000000000000000000000000000000000001` +- `beta` = `0x06f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89` diff --git a/starknet-curve/src/curve_params.rs b/starknet-curve/src/curve_params.rs index 5368cbc4..5e7cd3e8 100644 --- a/starknet-curve/src/curve_params.rs +++ b/starknet-curve/src/curve_params.rs @@ -1,6 +1,8 @@ use starknet_types_core::curve::AffinePoint; use starknet_types_core::felt::Felt; +/// EC order of the STARK curve for ECDSA. Equals to +/// `0x0800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f`. pub const EC_ORDER: Felt = Felt::from_raw([ 369010039416812937, 9, @@ -8,6 +10,14 @@ pub const EC_ORDER: Felt = Felt::from_raw([ 8939893405601011193, ]); +/// The alpha parameter of the STARK curve. Equals to +/// `0x0000000000000000000000000000000000000000000000000000000000000001`. +/// +/// The alpha parameter is used in the curve definition as: +/// +/// ```markdown +/// y^2 = x^3 + alpha * x + beta +/// ``` pub const ALPHA: Felt = Felt::from_raw([ 576460752303422960, 18446744073709551615, @@ -15,6 +25,14 @@ pub const ALPHA: Felt = Felt::from_raw([ 18446744073709551585, ]); +/// The beta parameter of the STARK curve. Equals to +/// `0x06f21413efbe40de150e596d72f7a8c5609ad26c15c915c1f4cdfcb99cee9e89`. +/// +/// The beta parameter is used in the curve definition as: +/// +/// ```markdown +/// y^2 = x^3 + alpha * x + beta +/// ``` pub const BETA: Felt = Felt::from_raw([ 88155977965380735, 12360725113329547591, @@ -22,6 +40,12 @@ pub const BETA: Felt = Felt::from_raw([ 3863487492851900874, ]); +/// Generator point of the STARK curve. +/// +/// Coordinates: +/// +/// - x: `0x01ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca` +/// - y: `0x005668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f` pub const GENERATOR: AffinePoint = AffinePoint::new_unchecked( Felt::from_raw([ 232005955912912577, @@ -37,6 +61,12 @@ pub const GENERATOR: AffinePoint = AffinePoint::new_unchecked( ]), ); +/// Shift point of the STARK curve. +/// +/// Coordinates: +/// +/// - x: `0x049ee3eba8c1600700ee1b87eb599f16716b0b1022947733551fde4050ca6804` +/// - y: `0x03ca0cfe4b3bc6ddf346d49d06ea0ed34e621062c0e056c1d0405d266e10268a` pub const SHIFT_POINT: AffinePoint = AffinePoint::new_unchecked( Felt::from_raw([ 316327189671755572, @@ -52,6 +82,12 @@ pub const SHIFT_POINT: AffinePoint = AffinePoint::new_unchecked( ]), ); +/// The P0 constant of the STARK curve. +/// +/// Coordinates: +/// +/// - x: `0x0234287dcbaffe7f969c748655fca9e58fa8120b6d56eb0c1080d17957ebe47b` +/// - y: `0x03b056f100f96fb21e889527d41f4e39940135dd7a6c94cc6ed0268ee89e5615` pub const PEDERSEN_P0: AffinePoint = AffinePoint::new_unchecked( Felt::from_raw([ 241691544791834578, @@ -67,6 +103,12 @@ pub const PEDERSEN_P0: AffinePoint = AffinePoint::new_unchecked( ]), ); +/// The P1 constant of the STARK curve. +/// +/// Coordinates: +/// +/// - x: `0x04fa56f376c83db33f9dab2656558f3399099ec1de5e3018b7a6932dba8aa378` +/// - y: `0x03fa0984c931c9e38113e0c0e47e4401562761f92a7a23b45168f4e80ff5b54d` pub const PEDERSEN_P1: AffinePoint = AffinePoint::new_unchecked( Felt::from_raw([ 253000153565733272, @@ -82,6 +124,12 @@ pub const PEDERSEN_P1: AffinePoint = AffinePoint::new_unchecked( ]), ); +/// The P2 constant of the STARK curve. +/// +/// Coordinates: +/// +/// - x: `0x04ba4cc166be8dec764910f75b45f74b40c690c74709e90f3aa372f0bd2d6997` +/// - y: `0x0040301cf5c1751f4b971e46c4ede85fcac5c59a5ce5ae7c48151f27b24b219c` pub const PEDERSEN_P2: AffinePoint = AffinePoint::new_unchecked( Felt::from_raw([ 338510149841406402, @@ -97,6 +145,12 @@ pub const PEDERSEN_P2: AffinePoint = AffinePoint::new_unchecked( ]), ); +/// The P3 constant of the STARK curve. +/// +/// Coordinates: +/// +/// - x: `0x054302dcb0e6cc1c6e44cca8f61a63bb2ca65048d53fb325d36ff12c49a58202` +/// - y: `0x01b77b3e37d13504b348046268d8ae25ce98ad783c25561a879dcc77e99c2426` pub const PEDERSEN_P3: AffinePoint = AffinePoint::new_unchecked( Felt::from_raw([ 425493972656615276, diff --git a/starknet-curve/src/lib.rs b/starknet-curve/src/lib.rs index a092b315..b336e9cb 100644 --- a/starknet-curve/src/lib.rs +++ b/starknet-curve/src/lib.rs @@ -1,4 +1,7 @@ +//! A library with constant parameters for the Stark elliptic curve. + +#![deny(missing_docs)] #![no_std] -#![doc = include_str!("../README.md")] +/// Module containing the Stark elliptic curve parameters. pub mod curve_params; From 02f22092f6a76d116889ead9cb5f71b537f09b22 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Sat, 27 Jul 2024 23:30:10 +0800 Subject: [PATCH 21/54] docs: add docs for `starknet-crypto` (#634) --- starknet-accounts/src/single_owner.rs | 12 ++++---- starknet-crypto/README.md | 10 +++++- starknet-crypto/src/ecdsa.rs | 44 ++++++++++++++++----------- starknet-crypto/src/error.rs | 18 +++++++++-- starknet-crypto/src/lib.rs | 18 ++++++++++- starknet-crypto/src/pedersen_hash.rs | 6 ++-- starknet-crypto/src/poseidon_hash.rs | 2 +- starknet-crypto/src/rfc6979.rs | 8 ++--- 8 files changed, 81 insertions(+), 37 deletions(-) diff --git a/starknet-accounts/src/single_owner.rs b/starknet-accounts/src/single_owner.rs index 4fc44ede..c615faf2 100644 --- a/starknet-accounts/src/single_owner.rs +++ b/starknet-accounts/src/single_owner.rs @@ -47,13 +47,13 @@ where { /// Create a new account controlled by a single signer. /// - /// ### Arguments + /// ### Parameters /// - /// * `provider`: A `Provider` implementation that provides access to the Starknet network. - /// * `signer`: A `Signer` implementation that can generate valid signatures for this account. - /// * `address`: Account contract address. - /// * `chain_id`: Network chain ID. - /// * `encoding`: How `__execute__` calldata should be encoded. + /// - `provider`: A `Provider` implementation that provides access to the Starknet network. + /// - `signer`: A `Signer` implementation that can generate valid signatures for this account. + /// - `address`: Account contract address. + /// - `chain_id`: Network chain ID. + /// - `encoding`: How `__execute__` calldata should be encoded. pub const fn new( provider: P, signer: S, diff --git a/starknet-crypto/README.md b/starknet-crypto/README.md index c4790d62..3af6bc0e 100644 --- a/starknet-crypto/README.md +++ b/starknet-crypto/README.md @@ -1,6 +1,14 @@ # Low-level cryptography utilities for Starknet -`starknet-crypto` contains utilities for performing **low-level** cryptographic operations in Starknet. +`starknet-crypto` contains utilities for performing **low-level** cryptographic operations in Starknet: + +- ECDSA operations + - Signing hashes + - Verifying signatures + - Recovering public keys from signatures +- Pedersen hash +- Poseidon hash +- RFC-6979 > _You're advised to use high-level crypto utilities implemented by the `starknet-core` crate (or use it through the `starknet::core` re-export) if you're not familiar with cryptographic primitives. Using these low-level functions incorrectly could result in leaking your private key, for example._ diff --git a/starknet-crypto/src/ecdsa.rs b/starknet-crypto/src/ecdsa.rs index ae15e181..066add30 100644 --- a/starknet-crypto/src/ecdsa.rs +++ b/starknet-crypto/src/ecdsa.rs @@ -7,6 +7,14 @@ use crate::{ use starknet_types_core::curve::{AffinePoint, ProjectivePoint}; use starknet_types_core::felt::Felt; +/// The (exclusive) upper bound on many ECDSA-related elements based on the original C++ +/// implementation from [`crypto-cpp`](https://github.com/starkware-libs/crypto-cpp). +/// +/// The C++ implementation [imposes](https://github.com/starkware-libs/crypto-cpp/blob/78e3ed8dc7a0901fe6d62f4e99becc6e7936adfd/src/starkware/crypto/ecdsa.cc#L23) +/// an upper bound of `0x0800000000000000000000000000000000000000000000000000000000000000`. +/// +/// When a compuated value is greater than or equal to this bound, the modulus is taken to ensure +/// the resulting value falls under the bound. const ELEMENT_UPPER_BOUND: Felt = Felt::from_raw([ 576459263475450960, 18446744073709255680, @@ -14,7 +22,7 @@ const ELEMENT_UPPER_BOUND: Felt = Felt::from_raw([ 18446743986131435553, ]); -/// Stark ECDSA signature +/// Stark ECDSA signature. #[derive(Debug)] pub struct Signature { /// The `r` value of a signature @@ -23,7 +31,7 @@ pub struct Signature { pub s: Felt, } -/// Stark ECDSA signature with `v` +/// Stark ECDSA signature with `v`, useful for recovering the public key. #[derive(Debug)] pub struct ExtendedSignature { /// The `r` value of a signature @@ -70,9 +78,9 @@ impl core::fmt::Display for ExtendedSignature { /// Computes the public key given a Stark private key. /// -/// ### Arguments +/// ### Parameters /// -/// * `private_key`: The private key +/// - `private_key`: The private key. pub fn get_public_key(private_key: &Felt) -> Felt { mul_by_bits(&GENERATOR, private_key) .to_affine() @@ -82,11 +90,11 @@ pub fn get_public_key(private_key: &Felt) -> Felt { /// Computes ECDSA signature given a Stark private key and message hash. /// -/// ### Arguments +/// ### Parameters /// -/// * `private_key`: The private key -/// * `message`: The message hash -/// * `k`: A random `k` value. You **MUST NOT** use the same `k` on different signatures +/// - `private_key`: The private key. +/// - `message`: The message hash. +/// - `k`: A random `k` value. You **MUST NOT** use the same `k` on different signatures. pub fn sign(private_key: &Felt, message: &Felt, k: &Felt) -> Result { if message >= &ELEMENT_UPPER_BOUND { return Err(SignError::InvalidMessageHash); @@ -120,12 +128,12 @@ pub fn sign(private_key: &Felt, message: &Felt, k: &Felt) -> Result Result { if message >= &ELEMENT_UPPER_BOUND { return Err(VerifyError::InvalidMessageHash); @@ -162,12 +170,12 @@ pub fn verify(public_key: &Felt, message: &Felt, r: &Felt, s: &Felt) -> Result Result { if message >= &ELEMENT_UPPER_BOUND { return Err(RecoverError::InvalidMessageHash); diff --git a/starknet-crypto/src/error.rs b/starknet-crypto/src/error.rs index 6f42fe15..b21e7f2d 100644 --- a/starknet-crypto/src/error.rs +++ b/starknet-crypto/src/error.rs @@ -1,8 +1,11 @@ mod sign_error { - /// Errors when performing ECDSA [`sign`](fn.sign) operations + /// Errors when performing ECDSA [`sign`](fn.sign) operations. #[derive(Debug)] pub enum SignError { + /// The message hash is not in the range of `[0, 2^251)`. InvalidMessageHash, + /// The random `k` value results in an invalid signature. A different `k` value should be + /// used instead, typically by using a new seed per RFC-6979. InvalidK, } @@ -21,12 +24,16 @@ mod sign_error { pub use sign_error::SignError; mod verify_error { - /// Errors when performing ECDSA [`verify`](fn.verify) operations + /// Errors when performing ECDSA [`verify`](fn.verify) operations. #[derive(Debug)] pub enum VerifyError { + /// The public key is not a valid point on the STARK curve. InvalidPublicKey, + /// The message hash is not in the range of `[0, 2^251)`. InvalidMessageHash, + /// The `r` value is not in the range of `[0, 2^251)`. InvalidR, + /// The `s` value is not in the range of `[0, 2^251)`. InvalidS, } @@ -47,12 +54,17 @@ mod verify_error { pub use verify_error::VerifyError; mod recover_error { - /// Errors when performing ECDSA [`recover`](fn.recover) operations + /// Errors when performing ECDSA [`recover`](fn.recover) operations. #[derive(Debug)] pub enum RecoverError { + /// The message hash is not in the range of `[0, 2^251)`. InvalidMessageHash, + /// The `r` value is not in the range of `[0, 2^251)`. InvalidR, + /// The `s` value is not in the range of `[0, + /// 0x0800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f)`. InvalidS, + /// The `v` value is neither `0` nor `1`. InvalidV, } diff --git a/starknet-crypto/src/lib.rs b/starknet-crypto/src/lib.rs index 551141e9..321f4e5f 100644 --- a/starknet-crypto/src/lib.rs +++ b/starknet-crypto/src/lib.rs @@ -1,5 +1,21 @@ +//! Low-level cryptography utilities for Starknet. Features include: +//! +//! - ECDSA operations +//! - [Signing hashes](fn.sign) +//! - [Verifying signatures](fn.verify) +//! - [Recovering public keys from signatures](fn.recover) +//! - [Pedersen hash](fn.pedersen_hash) +//! - Poseidon hash +//! - [RFC-6979](fn.rfc6979_generate_k) +//! +//! # Warning +//! +//! You're advised to use high-level crypto utilities implemented by the `starknet-core` crate if +//! you're not familiar with cryptographic primitives. Using these low-level functions incorrectly +//! could result in catastrophic consequences like leaking your private key. + +#![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -#![doc = include_str!("../README.md")] #[allow(unused_extern_crates)] #[cfg(all(not(feature = "std"), any(test, feature = "alloc")))] diff --git a/starknet-crypto/src/pedersen_hash.rs b/starknet-crypto/src/pedersen_hash.rs index 5080a826..275b5d81 100644 --- a/starknet-crypto/src/pedersen_hash.rs +++ b/starknet-crypto/src/pedersen_hash.rs @@ -5,10 +5,10 @@ use starknet_types_core::{ /// Computes the Starkware version of the Pedersen hash of x and y. All inputs are little-endian. /// -/// ### Arguments +/// ### Parameters /// -/// * `x`: The x coordinate -/// * `y`: The y coordinate +/// - `x`: The x coordinate. +/// - `y`: The y coordinate. pub fn pedersen_hash(x: &Felt, y: &Felt) -> Felt { Pedersen::hash(x, y) } diff --git a/starknet-crypto/src/poseidon_hash.rs b/starknet-crypto/src/poseidon_hash.rs index 18a4d4e9..4155f056 100644 --- a/starknet-crypto/src/poseidon_hash.rs +++ b/starknet-crypto/src/poseidon_hash.rs @@ -3,7 +3,7 @@ use starknet_types_core::{felt::Felt, hash::Poseidon}; -/// A hasher for Starknet Poseidon hash. +/// A stateful hasher for Starknet Poseidon hash. /// /// Using this hasher is the same as calling [`poseidon_hash_many`]. #[derive(Debug, Default)] diff --git a/starknet-crypto/src/rfc6979.rs b/starknet-crypto/src/rfc6979.rs index cd7ea7da..550040df 100644 --- a/starknet-crypto/src/rfc6979.rs +++ b/starknet-crypto/src/rfc6979.rs @@ -9,11 +9,11 @@ const EC_ORDER: U256 = /// Deterministically generate ephemeral scalar `k` based on RFC 6979. /// -/// ### Arguments +/// ### Parameters /// -/// * `message_hash`: message hash -/// * `private_key`: private key -/// * `seed`: extra seed for additional entropy +/// - `message_hash`: Message hash. +/// - `private_key`: Private key. +/// - `seed`: Extra seed for additional entropy. pub fn generate_k(message_hash: &Felt, private_key: &Felt, seed: Option<&Felt>) -> Felt { // The message hash padding as implemented in `cairo-lang` is not needed here. The hash is // padded in `cairo-lang` only to make sure the lowest 4 bits won't get truncated, but here it's From c2a1d431bcb197cec5ccd9053e5696b69b264dc4 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Sun, 28 Jul 2024 14:09:42 +0800 Subject: [PATCH 22/54] test: run tests against pathfinder (#635) --- starknet-accounts/tests/single_owner_account.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starknet-accounts/tests/single_owner_account.rs b/starknet-accounts/tests/single_owner_account.rs index 46d895f4..bc1febe8 100644 --- a/starknet-accounts/tests/single_owner_account.rs +++ b/starknet-accounts/tests/single_owner_account.rs @@ -32,7 +32,7 @@ fn create_sequencer_client() -> SequencerGatewayProvider { fn create_jsonrpc_client() -> JsonRpcClient { let rpc_url = std::env::var("STARKNET_RPC") - .unwrap_or_else(|_| "https://juno.rpc.sepolia.starknet.rs/rpc/v0_7".into()); + .unwrap_or_else(|_| "https://pathfinder.rpc.sepolia.starknet.rs/rpc/v0_7".into()); JsonRpcClient::new(HttpTransport::new(url::Url::parse(&rpc_url).unwrap())) } From 4d5b408e53d92f29a119d6800aca88f5df34cccc Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 29 Jul 2024 01:04:41 +0800 Subject: [PATCH 23/54] docs: add docs for `starknet-core` (#636) --- starknet-core/src/chain_id.rs | 4 + starknet-core/src/crypto.rs | 20 +++ starknet-core/src/lib.rs | 9 +- starknet-core/src/serde/byte_array.rs | 3 + starknet-core/src/serde/mod.rs | 2 + .../src/serde/unsigned_field_element.rs | 4 + starknet-core/src/types/codegen.rs | 3 +- starknet-core/src/types/contract/legacy.rs | 155 ++++++++++++++++- starknet-core/src/types/contract/mod.rs | 162 +++++++++++++++++- starknet-core/src/types/eth_address.rs | 10 ++ starknet-core/src/types/execution_result.rs | 14 +- starknet-core/src/types/hash_256.rs | 9 + starknet-core/src/types/mod.rs | 120 ++++++++++++- starknet-core/src/types/msg.rs | 6 + starknet-core/src/types/receipt_block.rs | 15 +- starknet-core/src/types/u256.rs | 46 ++--- starknet-core/src/utils.rs | 36 +++- 17 files changed, 584 insertions(+), 34 deletions(-) diff --git a/starknet-core/src/chain_id.rs b/starknet-core/src/chain_id.rs index 715dc437..8ec150bc 100644 --- a/starknet-core/src/chain_id.rs +++ b/starknet-core/src/chain_id.rs @@ -1,5 +1,6 @@ use starknet_types_core::felt::Felt; +/// The chain identifier for Starknet Mainnet. A Cairo short string encoding of `SN_MAIN`. pub const MAINNET: Felt = Felt::from_raw([ 502562008147966918, 18446744073709551615, @@ -7,6 +8,7 @@ pub const MAINNET: Felt = Felt::from_raw([ 17696389056366564951, ]); +/// The chain identifier for Starknet Goerli. A Cairo short string encoding of `SN_GOERLI`. #[deprecated = "The Goerli testnet has been shutdown"] pub const TESTNET: Felt = Felt::from_raw([ 398700013197595345, @@ -15,6 +17,7 @@ pub const TESTNET: Felt = Felt::from_raw([ 3753493103916128178, ]); +/// The chain identifier for Starknet Goerli 2. A Cairo short string encoding of `SN_GOERLI2`. #[deprecated = "The Goerli testnet has been shutdown"] pub const TESTNET2: Felt = Felt::from_raw([ 33650220878420990, @@ -23,6 +26,7 @@ pub const TESTNET2: Felt = Felt::from_raw([ 1663542769632127759, ]); +/// The chain identifier for Starknet Sepolia. A Cairo short string encoding of `SN_SEPOLIA`. pub const SEPOLIA: Felt = Felt::from_raw([ 507980251676163170, 18446744073709551615, diff --git a/starknet-core/src/crypto.rs b/starknet-core/src/crypto.rs index 1977f4da..fbaf6973 100644 --- a/starknet-core/src/crypto.rs +++ b/starknet-core/src/crypto.rs @@ -6,16 +6,23 @@ use starknet_crypto::{rfc6979_generate_k, sign, verify, SignError, VerifyError}; mod errors { use core::fmt::{Display, Formatter, Result}; + /// Errors when performing ECDSA [`sign`](fn.ecdsa_sign) operations. #[derive(Debug)] pub enum EcdsaSignError { + /// The message hash is not in the range of `[0, 2^251)`. MessageHashOutOfRange, } #[derive(Debug)] + /// Errors when performing ECDSA [`verify`](fn.ecdsa_verify) operations. pub enum EcdsaVerifyError { + /// The message hash is not in the range of `[0, 2^251)`. MessageHashOutOfRange, + /// The public key is not a valid point on the STARK curve. InvalidPublicKey, + /// The `r` value is not in the range of `[0, 2^251)`. SignatureROutOfRange, + /// The `s` value is not in the range of `[0, 2^251)`. SignatureSOutOfRange, } @@ -46,6 +53,16 @@ mod errors { } pub use errors::{EcdsaSignError, EcdsaVerifyError}; +/// Computes the Pedersen hash of a list of [`Felt`]. +/// +/// The hash is computed by starting with `0`, hashing it recursively against all elements in +/// the list, and finally also hashing against the length of the list. +/// +/// For example, calling `compute_hash_on_elements([7, 8])` would return: +/// +/// ```markdown +/// pedersen_hash(pedersen_hash(pedersen_hash(0, 7)), 8), 2) +/// ``` pub fn compute_hash_on_elements<'a, ESI, II>(data: II) -> Felt where ESI: ExactSizeIterator, @@ -62,6 +79,8 @@ where pedersen_hash(¤t_hash, &data_len) } +/// Signs a hash using deterministic ECDSA on the STARK curve. The signature returned can be used +/// to recover the public key. pub fn ecdsa_sign( private_key: &Felt, message_hash: &Felt, @@ -89,6 +108,7 @@ pub fn ecdsa_sign( } } +/// Verified an ECDSA signature on the STARK curve. pub fn ecdsa_verify( public_key: &Felt, message_hash: &Felt, diff --git a/starknet-core/src/lib.rs b/starknet-core/src/lib.rs index f689809b..676c1bed 100644 --- a/starknet-core/src/lib.rs +++ b/starknet-core/src/lib.rs @@ -1,15 +1,22 @@ +//! Core data types and utilities for Starknet. + +#![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::comparison_chain)] -#![doc = include_str!("../README.md")] +/// Module containing custom serialization/deserialization implementations. pub mod serde; +/// Module containing core types for representing objects in Starknet. pub mod types; +/// High-level utilities for cryptographic operations used in Starknet. pub mod crypto; +/// Utilities for performing commonly used algorithms in Starknet. pub mod utils; +/// Chain IDs for commonly used public Starknet networks. pub mod chain_id; extern crate alloc; diff --git a/starknet-core/src/serde/byte_array.rs b/starknet-core/src/serde/byte_array.rs index 0d2bb46e..70b6ed6e 100644 --- a/starknet-core/src/serde/byte_array.rs +++ b/starknet-core/src/serde/byte_array.rs @@ -1,3 +1,4 @@ +/// Serializing and deserializing [`Vec`] with base64 encoding. pub mod base64 { use alloc::{fmt::Formatter, format, vec::*}; @@ -6,6 +7,7 @@ pub mod base64 { struct Base64Visitor; + /// Serializes [`Vec`] as base64 string. pub fn serialize(value: T, serializer: S) -> Result where S: Serializer, @@ -14,6 +16,7 @@ pub mod base64 { serializer.serialize_str(&STANDARD.encode(value.as_ref())) } + /// Deserializes [`Vec`] from base64 string. pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, diff --git a/starknet-core/src/serde/mod.rs b/starknet-core/src/serde/mod.rs index c414c706..abe1d561 100644 --- a/starknet-core/src/serde/mod.rs +++ b/starknet-core/src/serde/mod.rs @@ -1,5 +1,7 @@ +/// Custom serialization/deserialization implementations for [`Vec`]. pub mod byte_array; +/// Custom serialization/deserialization implementations for [`Felt`]. pub mod unsigned_field_element; pub(crate) mod num_hex; diff --git a/starknet-core/src/serde/unsigned_field_element.rs b/starknet-core/src/serde/unsigned_field_element.rs index 87f311cb..f42606a8 100644 --- a/starknet-core/src/serde/unsigned_field_element.rs +++ b/starknet-core/src/serde/unsigned_field_element.rs @@ -12,12 +12,16 @@ use starknet_types_core::felt::Felt; const PRIME: U256 = U256::from_be_hex("0800000000000011000000000000000000000000000000000000000000000001"); +/// Serialize/deserialize [`Felt`] as hex strings. For use with `serde_with`. #[derive(Debug)] pub struct UfeHex; +/// Serialize/deserialize [`Option`] as hex strings. For use with `serde_with`. #[derive(Debug)] pub struct UfeHexOption; +/// Serialize/deserialize [`Option`] as hex strings in a pending block hash context. For use +/// with `serde_with`. #[derive(Debug)] pub struct UfePendingBlockHash; diff --git a/starknet-core/src/types/codegen.rs b/starknet-core/src/types/codegen.rs index 2d7e0d02..a4483a37 100644 --- a/starknet-core/src/types/codegen.rs +++ b/starknet-core/src/types/codegen.rs @@ -3,7 +3,7 @@ // https://github.com/xJonathanLEI/starknet-jsonrpc-codegen // Code generated with version: -// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen#fbd3aed2a08d6b29328e87ee0bbfb7e80f7051b0 +// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen#f1278dfb2ae57d319093421c038f6ec7a3dfba2f // These types are ignored from code generation. Implement them manually: // - `RECEIPT_BLOCK` @@ -24,6 +24,7 @@ // - `TXN` // - `TXN_RECEIPT` +#![allow(missing_docs)] #![allow(clippy::doc_markdown)] #![allow(clippy::missing_const_for_fn)] diff --git a/starknet-core/src/types/contract/legacy.rs b/starknet-core/src/types/contract/legacy.rs index 3803a218..4608bd7a 100644 --- a/starknet-core/src/types/contract/legacy.rs +++ b/starknet-core/src/types/contract/legacy.rs @@ -26,150 +26,234 @@ use flate2::{write::GzEncoder, Compression}; const API_VERSION: Felt = Felt::ZERO; +/// A legacy (Cairo 0) contract class in a representation identical to the compiler output. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyContractClass { + /// Contract ABI. pub abi: Vec, + /// Contract entrypoints. pub entry_points_by_type: RawLegacyEntryPoints, + /// The Cairo program of the contract containing the actual bytecode. pub program: LegacyProgram, } +/// Legacy (Cairo 0) contract entrypoints by types. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct RawLegacyEntryPoints { + /// Entrypoints of type `CONSTRUCTOR` used during contract deployment. pub constructor: Vec, + /// Entrypoints of type `EXTERNAL` used for invocations from outside contracts. pub external: Vec, + /// Entrypoints of type `L1_HANDLER` used for handling L1-to-L2 messages. pub l1_handler: Vec, } +/// Legacy (Cairo 0) program containing bytecode and other data necessary for execution. #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyProgram { + /// Attributes that provide additional context for certain sections of the bytecode. #[serde(skip_serializing_if = "Option::is_none")] pub attributes: Option>, + /// The list of Cairo builtins this program has access to. pub builtins: Vec, // This field was introduced in Cairo 0.10.0. By making it optional we're keeping compatibility // with older artifacts. This decision should be reviewd in the future. + /// Version of the compiler used to compile this contract. #[serde(skip_serializing_if = "Option::is_none")] pub compiler_version: Option, + /// The Cairo assembly bytecode of the contract. #[serde_as(as = "Vec")] pub data: Vec, + /// Debug information which is optionally emitted by the compiler. This field is not used for + /// class declaration or class hash calculation. pub debug_info: Option, + /// Legacy hints for non-determinism. pub hints: BTreeMap>, + /// A map of identifiers by name. pub identifiers: BTreeMap, + /// The main scope/namespace where all identifiers this program defines live in, usually + /// `__main__`. pub main_scope: String, // Impossible to use [Felt] here as by definition field elements are smaller // than prime + /// The STARK field prime. pub prime: String, + /// Data for tracking + /// [references](https://docs.cairo-lang.org/how_cairo_works/consts.html#references). pub reference_manager: LegacyReferenceManager, } +/// An legacy (Cairo 0) contract entrypoint for translating a selector to a bytecode offset. #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct RawLegacyEntryPoint { + /// Offset in the bytecode. pub offset: LegacyEntrypointOffset, + /// Selector of the entrypoint, usually computed as the Starknet Keccak of the function name. #[serde_as(as = "UfeHex")] pub selector: Felt, } +/// Legacy (Cairo 0) program attribute that provide additional context for certain sections of the +/// bytecode. +/// +/// Attributes are usually used for providing error messages when an assertion fails. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyAttribute { + /// The scopes from which the attribute is accessible. #[serde(default)] pub accessible_scopes: Vec, + /// The ending PC of the segment that has access to the attribute. pub end_pc: u64, + /// Data needed for tracking the allocation pointer. #[serde(skip_serializing_if = "Option::is_none")] pub flow_tracking_data: Option, + /// Name of the attribute. pub name: String, + /// The starting PC of the segment that has access to the attribute. pub start_pc: u64, + /// Value of the attribute. pub value: String, } +/// Debug information generated by the legacy (Cairo 0) compiler. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyDebugInfo { /// A partial map from file name to its content. Files that are not in the map, are assumed to /// exist in the file system. pub file_contents: BTreeMap, - /// A map from (relative) PC to the location of the instruction + /// A map from (relative) PC to the location of the instruction. pub instruction_locations: BTreeMap, } +/// Legacy (Cairo 0) hints for introducing non-determinism into a Cairo program. +/// +/// These hints are implemented in Python that execute arbitrary code to fill Cairo VM memory. In +/// a public network like Starknet, a predefined list of hints are whitelisted to prevent deployment +/// of malicious code. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyHint { + /// The scopes from which the hint is accessible. pub accessible_scopes: Vec, + /// The Python code of the hint. pub code: String, + /// Data needed for tracking the allocation pointer. pub flow_tracking_data: LegacyFlowTrackingData, } +/// Legacy (Cairo 0) program identifiers. +/// +/// These are needed mostly to allow Python hints to work, as hints are allowed to reference Cairo +/// identifiers (e.g. variables) by name, which would otherwise be lost during compilation. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyIdentifier { + /// Decorators of the identifier, used for functions. #[serde(skip_serializing_if = "Option::is_none")] pub decorators: Option>, + /// The Cairo type, used for type definitions. #[serde(skip_serializing_if = "Option::is_none")] pub cairo_type: Option, + /// The fully-qualified name, used for struct definitions. #[serde(skip_serializing_if = "Option::is_none")] pub full_name: Option, + /// The list of members, used for struct definitions. #[serde(skip_serializing_if = "Option::is_none")] pub members: Option>, + /// The list of references, used for references. #[serde(skip_serializing_if = "Option::is_none")] pub references: Option>, + /// The size in the number of field elements, used for struct definitions. #[serde(skip_serializing_if = "Option::is_none")] pub size: Option, + /// The program counter, used for functions. #[serde(skip_serializing_if = "Option::is_none")] pub pc: Option, + /// The fully-qualified name of the identifier that this identifier points to, used for + /// aliases. #[serde(skip_serializing_if = "Option::is_none")] pub destination: Option, + /// Type of the identifier. pub r#type: String, + /// Value of the identifier, used for constants. #[serde(skip_serializing_if = "Option::is_none")] pub value: Option>, } +/// Data needed for tracking +/// [references](https://docs.cairo-lang.org/how_cairo_works/consts.html#references). #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyReferenceManager { + /// The list of references. pub references: Vec, } -/// This field changed from hex string to number on 0.11.0. +/// The legacy (Cairo 0) contract entrypoint offset, in either hexadecimal or numeric +/// representation. +/// +/// This type is needed as the entrypoint offset field changed from hex string to number on 0.11.0. +/// The type allows serializing older contracts in their original forms. #[derive(Debug, Copy, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] #[serde(untagged)] pub enum LegacyEntrypointOffset { + /// Offset with hexadecimal representation. U64AsHex(#[serde(with = "u64_hex")] u64), + /// Offset with numeric representation. U64AsInt(u64), } +/// Legacy (Cairo 0) instruction location for use in debug info. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyInstructionLocation { + /// The scopes from which the instruction is accessible. pub accessible_scopes: Vec, // This field is serialized as `null` instead of skipped + /// Data needed for tracking the allocation pointer. pub flow_tracking_data: Option, + /// Physical code locations of hints in the source . pub hints: Vec, + /// Physical code location of the instruction in the source. pub inst: LegacyLocation, } +/// Legacy (Cairo 0) struct member as part of a struct definition identifier. Used in +/// [`LegacyIdentifier`] for enabling hints to access identifiers by name. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyIdentifierMember { + /// The Cairo type of this struct field. pub cairo_type: String, + /// Offset of the field calculated as the total size of all the fields before this member in the + /// number of field elements. pub offset: u64, } +/// Cairo 0 [references](https://docs.cairo-lang.org/how_cairo_works/consts.html#references). #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyReference { + /// Data needed for tracking the allocation pointer. pub ap_tracking_data: LegacyApTrackingData, + /// Program counter value. pub pc: u64, + /// Value of the reference. pub value: String, } +// Missing docs allowed as it's unclear what exactly how type works in the Cairo program. +#[allow(missing_docs)] #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyFlowTrackingData { @@ -177,26 +261,37 @@ pub struct LegacyFlowTrackingData { pub reference_ids: BTreeMap, } +/// Physical location of a legacy (Cairo 0) hint in source for use in debug info. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyHintLocation { + /// The physical location of the hint. pub location: LegacyLocation, - /// The number of new lines following the "%{" symbol + /// The number of new lines following the "%{" symbol. pub n_prefix_newlines: u64, } +/// The physical location in source of a certain code segment for use in debug info. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyLocation { + /// The ending column number. pub end_col: u64, + /// The ending line number. pub end_line: u64, + /// The file path or content. pub input_file: LegacyInputFile, + /// Location of the parent instruction, if any. #[serde(skip_serializing_if = "Option::is_none")] pub parent_location: Option, + /// The starting column number. pub start_col: u64, + /// The starting line number. pub start_line: u64, } +// Missing docs allowed as it's unclear what exactly how type works in the Cairo program. +#[allow(missing_docs)] #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyApTrackingData { @@ -204,73 +299,118 @@ pub struct LegacyApTrackingData { pub offset: u64, } +/// Input file path or content for use in debug info. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct LegacyInputFile { + /// Path to file in the file system. #[serde(skip_serializing_if = "Option::is_none")] pub filename: Option, + /// Full content of the file, typically for ephemeral files. #[serde(skip_serializing_if = "Option::is_none")] pub content: Option, } +/// Location of the parent instruction for use in debug info. +/// +/// It's used (?) for generating human-readable stack traces. #[derive(Debug, Clone)] pub struct LegacyParentLocation { + /// Location of the parent instruction. pub location: Box, + /// A human-readable remark usually in the form similar to "while trying to xxx". pub remark: String, } +/// Legacy (Cairo 0) contract ABI item. #[derive(Debug, Clone)] pub enum RawLegacyAbiEntry { + /// Constructor ABI entry. Constructor(RawLegacyConstructor), + /// Function ABI entry. Function(RawLegacyFunction), + /// Struct ABI entry. Struct(RawLegacyStruct), + /// L1 handler ABI entry. L1Handler(RawLegacyL1Handler), + /// Event ABI entry. Event(RawLegacyEvent), } +/// Legacy (Cairo 0) contract ABI representation of a constructor. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RawLegacyConstructor { + /// Inputs to the constructor. pub inputs: Vec, + /// Name of the constructor. pub name: String, + /// Outputs of the constructor. pub outputs: Vec, } +/// Legacy (Cairo 0) contract ABI representation of a function. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RawLegacyFunction { + /// Inputs to the function. pub inputs: Vec, + /// Name of the function. pub name: String, + /// Outputs of the function. pub outputs: Vec, + /// State mutability of the function. + /// + /// Note that this is currently not enforced by the compiler. It's therefore only as accurate as + /// the code author annotating them is. #[serde(skip_serializing_if = "Option::is_none")] pub state_mutability: Option, } +/// Legacy (Cairo 0) contract ABI representation of a struct. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RawLegacyStruct { + /// Fields of the struct. pub members: Vec, + /// Name of the struct. pub name: String, + /// Size of the struct in the number of field elements. pub size: u64, } +/// Legacy (Cairo 0) contract ABI representation of an L1 handler. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RawLegacyL1Handler { + /// Inputs to the L1 handler function. pub inputs: Vec, + /// Name of the L1 handler function. pub name: String, + /// Outputs of the L1 handler function. pub outputs: Vec, } +/// Legacy (Cairo 0) contract ABI representation of an event. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RawLegacyEvent { + /// Data of the events for the unindexed event fields. pub data: Vec, + /// Keys of the events. + /// + /// This usually includes at least one element as the Starknet Keccak of the event name. + /// Additional keys are used for indexed event fields, if any. pub keys: Vec, + /// Name of the events. pub name: String, } +/// Legacy (Cairo 0) contract ABI representation of a struct field. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct RawLegacyMember { + /// Name of the struct field. pub name: String, + /// Total size of the fields in the struct before this field. pub offset: u64, + /// Cairo type of the struct field. pub r#type: String, } @@ -394,6 +534,7 @@ impl<'de> Deserialize<'de> for RawLegacyAbiEntry { } impl LegacyContractClass { + /// Computes the class hash of the legacy (Cairo 0) class. pub fn class_hash(&self) -> Result { let mut elements = Vec::new(); @@ -449,6 +590,12 @@ impl LegacyContractClass { Ok(compute_hash_on_elements(&elements)) } + /// Computes the "hinted" class hash of the legacy (Cairo 0) class. + /// + /// This is known as the "hinted" hash as it isn't possible to directly calculate, and thus + /// prove the correctness of, this hash, since it involves JSON serialization. Instead, this + /// hash is always calculated outside of the Cairo VM, and then fed to the Cairo program as a + /// hinted value. pub fn hinted_class_hash(&self) -> Result { #[serde_as] #[derive(Serialize)] @@ -471,6 +618,7 @@ impl LegacyContractClass { Ok(starknet_keccak(serialized.as_bytes())) } + /// Compresses the legacy (Cairo 0) class with gzip, as needed for class declaration. #[cfg(feature = "std")] pub fn compress(&self) -> Result { Ok(CompressedLegacyContractClass { @@ -488,6 +636,7 @@ impl LegacyContractClass { } impl LegacyProgram { + /// Compresses the legacy (Cairo 0) program with gzip. #[cfg(feature = "std")] pub fn compress(&self) -> Result, CompressProgramError> { use std::io::Write; diff --git a/starknet-core/src/types/contract/mod.rs b/starknet-core/src/types/contract/mod.rs index ba1b17ba..8d50753f 100644 --- a/starknet-core/src/types/contract/mod.rs +++ b/starknet-core/src/types/contract/mod.rs @@ -32,33 +32,52 @@ const PREFIX_COMPILED_CLASS_V1: Felt = Felt::from_raw([ 2291010424822318237, ]); +/// Cairo contract artifact in a representation identical to the compiler output. #[derive(Debug, Clone, Serialize)] #[serde(untagged)] #[allow(clippy::large_enum_variant)] pub enum ContractArtifact { + /// Sierra (Cairo 1) class. SierraClass(SierraClass), + /// Cairo assembly (CASM) class compiled from a Sierra class. CompiledClass(CompiledClass), + /// Legacy (Cairo 0) class LegacyClass(legacy::LegacyContractClass), } +/// A Sierra (Cairo 1) contract class in a representation identical to the compiler output. #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct SierraClass { + /// Sierra bytecode. #[serde_as(as = "Vec")] pub sierra_program: Vec, + /// Sierra class debug info. pub sierra_program_debug_info: SierraClassDebugInfo, + /// Sierra version. pub contract_class_version: String, + /// Contract entrypoints. pub entry_points_by_type: EntryPointsByType, + /// Contract ABI. pub abi: Vec, } +/// A Cairo assembly (CASM) class compiled from a Sierra class. +/// +/// The Sierra to CASM process is needed as the Cairo VM can only execute CASM, not Sierra bytecode. +/// However, if direct deployment of CASM were allowed, unsafe (unprovable) programs could be +/// deployed to a public network allowing for DOS attacks. Instead, only Sierra, an intermedia +/// representation that always compiles to safe (provable) CASM, is allowed to be deployed. #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct CompiledClass { + /// The STARK field prime. pub prime: String, + /// Version of the compiler used to compile this contract. pub compiler_version: String, + /// Cairo assembly bytecode. #[serde_as(as = "Vec")] pub bytecode: Vec, /// Represents the structure of the bytecode segments, using a nested list of segment lengths. @@ -66,189 +85,282 @@ pub struct CompiledClass { /// length 2 and the second is a node with 2 children of lengths 3 and 4. #[serde(default, skip_serializing_if = "Vec::is_empty")] pub bytecode_segment_lengths: Vec, + /// Hints for non-determinism. pub hints: Vec, + /// Same as `hints` but represented in Python code, which can be generated by the compiler but + /// is off by default. pub pythonic_hints: Option>, + /// Contract entrypoints. pub entry_points_by_type: CompiledClassEntrypointList, } +/// Debug information optionally generated by the compiler for mapping IDs to human-readable names. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct SierraClassDebugInfo { + /// Mapping from type IDs to names. pub type_names: Vec<(u64, String)>, + /// Mapping from libfunc IDs to names. pub libfunc_names: Vec<(u64, String)>, + /// Mapping from user function IDs to names. pub user_func_names: Vec<(u64, String)>, } +/// Cairo assembly (CASM) contract entrypoints by types. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct CompiledClassEntrypointList { + /// Entrypoints of type `EXTERNAL` used for invocations from outside contracts. pub external: Vec, + /// Entrypoints of type `L1_HANDLER` used for handling L1-to-L2 messages. pub l1_handler: Vec, + /// Entrypoints of type `CONSTRUCTOR` used during contract deployment. pub constructor: Vec, } +/// Sierra (Cairo 1) contract ABI item. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "snake_case")] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub enum AbiEntry { + /// Function ABI entry. Function(AbiFunction), + /// Event ABI entry. Event(AbiEvent), + /// Struct ABI entry. Struct(AbiStruct), + /// Enum ABI entry. Enum(AbiEnum), + /// Constructor ABI entry. Constructor(AbiConstructor), + /// Impl ABI entry. Impl(AbiImpl), + /// Interface ABI entry. Interface(AbiInterface), + /// L1 handler ABI entry. L1Handler(AbiFunction), } +/// Cairo assembly (CASM) hints for introducing non-determinism into a Cairo program. +/// +/// Unlike legacy (Cairo 0) hints which are arbitrary Python code, hints compiled from Sierra +/// bytecode come from a predefined list of hint specifications (e.g. `TestLessThanOrEqual`). #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Hint { + /// ID of the hint. pub id: u64, // For convenience we just treat it as an opaque JSON value here, unless a use case justifies // implementing the structure. (We no longer need the hints for the class hash anyways.) + /// Declarative specification of the hint. pub code: Vec, } +/// Same as [`Hint`] but is represented as Python code instead of a declarative specification. #[derive(Debug, Clone)] pub struct PythonicHint { + /// ID of the hint. pub id: u64, + /// Python code representation of the hint. pub code: Vec, } +/// An Cairo assembly (CASM) contract entrypoint for translating a selector to a bytecode offset. #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct CompiledClassEntrypoint { + /// Selector of the entrypoint, usually computed as the Starknet Keccak of the function name. #[serde_as(as = "UfeHex")] pub selector: Felt, + /// Offset in the bytecode. pub offset: u64, + /// The list of Cairo builtins used with this entrypoint. pub builtins: Vec, } +/// Sierra (Cairo 1) contract ABI representation of a function. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct AbiFunction { + /// Name of the function. pub name: String, + /// Inputs to the function. pub inputs: Vec, + /// Outputs of the function. pub outputs: Vec, + /// State mutability of the function. + /// + /// Note that this is currently not enforced by the compiler. It's therefore only as accurate as + /// the code author annotating them is. pub state_mutability: StateMutability, } +/// Sierra (Cairo 1) contract ABI representation of an event. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] #[serde(untagged)] pub enum AbiEvent { - /// Cairo 2.x ABI event entry + /// Cairo 2.x ABI event entry. Typed(TypedAbiEvent), - /// Cairo 1.x ABI event entry + /// Cairo 1.x ABI event entry. Untyped(UntypedAbiEvent), } +/// Cairo 2.x ABI event entry. #[derive(Debug, Clone, Deserialize)] #[serde(tag = "kind", rename_all = "snake_case")] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub enum TypedAbiEvent { + /// An event definition that's a struct. Struct(AbiEventStruct), + /// An event definition that's an enum. Enum(AbiEventEnum), } +/// Cairo 1.x ABI event entry. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct UntypedAbiEvent { + /// Name of the event. pub name: String, + /// Fields of the event. pub inputs: Vec, } +/// An event definition that's a struct. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct AbiEventStruct { + /// Name of the event struct. pub name: String, + /// Fields of the event struct. pub members: Vec, } +/// An event definition that's an enum. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct AbiEventEnum { + /// Name of the event enum. pub name: String, + /// Variants of the event enum. pub variants: Vec, } +/// Sierra (Cairo 1) contract ABI representation of a struct. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct AbiStruct { + /// Name of the struct. pub name: String, + /// Fields of the struct. pub members: Vec, } +/// Sierra (Cairo 1) contract ABI representation of a constructor. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct AbiConstructor { + /// Name of the constructor. pub name: String, + /// Inputs to the constructor. pub inputs: Vec, } +/// Sierra (Cairo 1) contract ABI representation of an interface implementation. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct AbiImpl { + /// Name of the interface implementation. pub name: String, + /// Name of the interface being implemented. pub interface_name: String, } +/// Sierra (Cairo 1) contract ABI representation of an interface. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct AbiInterface { + /// Name of the interface. pub name: String, + /// The shape of the interface. pub items: Vec, } +/// Sierra (Cairo 1) contract ABI representation of an enum. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct AbiEnum { + /// Name of the enum. pub name: String, + /// Variants of the enum. pub variants: Vec, } +/// A name and type pair for describing a struct field. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct AbiNamedMember { + /// Name of the field. pub name: String, + /// Type of the field. pub r#type: String, } +/// An output from a contract function. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct AbiOutput { + /// Type of the output. pub r#type: String, } +/// Struct field or enum variant of an event type. #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct EventField { + /// Name of the field or variant. pub name: String, + /// Type of the field or variant. pub r#type: String, + /// The role this field or variant plays as part of an event emission. pub kind: EventFieldKind, } +/// State mutability of a function. +/// +/// Note that this is currently not enforced by the compiler. It's therefore only as accurate as the +/// code author annotating them is. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum StateMutability { + /// The function is *annotated* as potentially state-changing. External, + /// The function is *annotated* as view-only, without changing the state. View, } +/// The role an event struct field or enum variant plays during an event emission. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum EventFieldKind { + /// Emitted as part of the event keys. Annotated with `#[key]`. Key, + /// Emitted as part of the event data. Annotated with `#[data]`. Data, + /// Serialized as a nested event. Nested, + /// Serialize as a flat event. Annotated with `#[flat]`. Flat, } +/// A node in a bytecode segment length tree. #[derive(Debug, Clone)] pub enum IntOrList { + /// A leave node of the tree representing a segment. Int(u64), + /// A branch node of the tree. List(Vec), } @@ -290,41 +402,68 @@ mod errors { use alloc::string::*; use core::fmt::{Display, Formatter, Result}; + /// Errors computing a class hash. #[derive(Debug)] pub enum ComputeClassHashError { + /// An invalid Cairo builtin name is found. This can happen when computing hashes for legacy + /// (Cairo 0) or Cairo assembly (CASM) classes. InvalidBuiltinName, + /// The total bytecode length is different than the implied length from + /// `bytecode_segment_lengths`. This can happen when computing Cairo assembly (CASM) class + /// hashes. BytecodeSegmentLengthMismatch(BytecodeSegmentLengthMismatchError), + /// A bytecode segment specified in `bytecode_segment_lengths` is invalid. This can happen + /// when computing Cairo assembly (CASM) class hashes. InvalidBytecodeSegment(InvalidBytecodeSegmentError), + /// The bytecode segments specified in `bytecode_segment_lengths` do not cover the full + /// range of bytecode. This can happen when computing Cairo assembly (CASM) class hashes. PcOutOfRange(PcOutOfRangeError), + /// Json serialization error. This can happen when serializing the contract ABI, as required + /// for computing hashes for legacy (Cairo 0) and Sierra (Cairo 1) classes. Json(JsonError), } + /// Errors compressing a legacy (Cairo 0) class. #[cfg(feature = "std")] #[derive(Debug)] pub enum CompressProgramError { + /// Json serialization error when serializing the contract ABI. Json(JsonError), + /// Gzip encoding error. Io(std::io::Error), } + /// Json serialization error represented as a string message. This is done instead of exposing + /// `serde_json` error types to avoid leaking implementation details and ease error handling. #[derive(Debug)] pub struct JsonError { pub(crate) message: String, } + /// The total bytecode length is different than the implied length from + /// `bytecode_segment_lengths`. #[derive(Debug)] pub struct BytecodeSegmentLengthMismatchError { + /// The total length implied by `bytecode_segment_lengths`. pub segment_length: usize, + /// The actual bytecode length. pub bytecode_length: usize, } + /// The bytecode segment is invalid as it's not consecutive with the prior segment. #[derive(Debug)] pub struct InvalidBytecodeSegmentError { + /// The expected program counter implied from a previous processed segment. pub visited_pc: u64, + /// The actual starting program counter as specified by the segment bytecode offset. pub segment_start: u64, } + /// The bytecode segments specified in `bytecode_segment_lengths` do not cover the full range of + /// bytecode. #[derive(Debug)] pub struct PcOutOfRangeError { + /// The first out-of-range program counter. pub pc: u64, } @@ -410,6 +549,7 @@ pub use errors::{ pub use errors::CompressProgramError; impl SierraClass { + /// Computes the class hash of the Sierra (Cairo 1) class. pub fn class_hash(&self) -> Result { // Technically we don't have to use the Pythonic JSON style here. Doing this just to align // with the official `cairo-lang` CLI. @@ -442,6 +582,22 @@ impl SierraClass { Ok(normalize_address(hasher.finalize())) } + /// Flattens the Sierra (Cairo 1) class by serializing the ABI using a Pythonic JSON + /// representation. The Pythoic JSON format is used for achieving the exact same output as that + /// of `cairo-lang`. + /// + /// The flattening is necessary for class declaration as the network does not deal with + /// structured contract ABI. Instead, any ABI is treated as an opaque string. + /// + /// Therefore, a process is needed for transforming a structured ABI into a string. This process + /// is called "flattening" in this library. The word is chosen instead of "serializing" as the + /// latter implies that there must be a way to "deserialize" the resulting string back to its + /// original, structured form. However, that would not be guaranteed. + /// + /// While it's true that the in *this* particular implementation, the string can *indeed* be + /// deserialized back to the original form, it's easy to imagine other flattening strategies + /// that are more destructive. In the future, this library will also allow custom flattening + /// implementations where the Pythoic style one presented here would merely be one of them. pub fn flatten(self) -> Result { let abi = to_string_pythonic(&self.abi).map_err(|err| JsonError { message: format!("{}", err), @@ -457,6 +613,7 @@ impl SierraClass { } impl FlattenedSierraClass { + /// Computes the class hash of the flattened Sierra (Cairo 1) class. pub fn class_hash(&self) -> Felt { let mut hasher = PoseidonHasher::new(); hasher.update(PREFIX_CONTRACT_CLASS_V0_1_0); @@ -481,6 +638,7 @@ impl FlattenedSierraClass { } impl CompiledClass { + /// Computes the class hash of the Cairo assembly (CASM) class. pub fn class_hash(&self) -> Result { let mut hasher = PoseidonHasher::new(); hasher.update(PREFIX_COMPILED_CLASS_V1); diff --git a/starknet-core/src/types/eth_address.rs b/starknet-core/src/types/eth_address.rs index 5bfa95bd..fccda237 100644 --- a/starknet-core/src/types/eth_address.rs +++ b/starknet-core/src/types/eth_address.rs @@ -12,6 +12,7 @@ const MAX_L1_ADDRESS: Felt = Felt::from_raw([ 18406070939574861858, ]); +/// Ethereum address represented with a 20-byte array. #[derive(Debug, Clone, PartialEq, Eq)] pub struct EthAddress { inner: [u8; 20], @@ -22,15 +23,20 @@ struct EthAddressVisitor; mod errors { use core::fmt::{Display, Formatter, Result}; + /// Errors parsing [`EthAddress`] from a hex string. #[derive(Debug)] pub enum FromHexError { + /// The hex string is not 40 hexadecimal characters in length without the `0x` prefix. UnexpectedLength, + /// The string contains non-hexadecimal characters. InvalidHexString, } + /// The [`Felt`] value is out of range for converting into [`EthAddress`]. #[derive(Debug)] pub struct FromFieldElementError; + /// The byte slice is out of range for converting into [`EthAddress`]. #[derive(Debug)] pub struct FromBytesSliceError; @@ -71,18 +77,22 @@ mod errors { pub use errors::{FromBytesSliceError, FromFieldElementError, FromHexError}; impl EthAddress { + /// Constructs [`EthAddress`] from a byte array. pub const fn from_bytes(bytes: [u8; 20]) -> Self { Self { inner: bytes } } + /// Parses [`EthAddress`] from a hex string. pub fn from_hex(hex: &str) -> Result { hex.parse() } + /// Constructs [`EthAddress`] from a [`Felt`]. pub fn from_felt(felt: &Felt) -> Result { felt.try_into() } + /// Gets a reference to the underlying byte array. pub const fn as_bytes(&self) -> &[u8; 20] { &self.inner } diff --git a/starknet-core/src/types/execution_result.rs b/starknet-core/src/types/execution_result.rs index b0d56a1c..fe2f83c1 100644 --- a/starknet-core/src/types/execution_result.rs +++ b/starknet-core/src/types/execution_result.rs @@ -4,14 +4,24 @@ use serde::{Deserialize, Serialize}; use super::TransactionExecutionStatus; -/// A more idiomatic way to access `execution_status` and `revert_reason`. +/// Execution result of a transaction. +/// +/// This struct ccorresponds to the `execution_status` and `revert_reason` fields of a transaction +/// receipt, capturing the fact that the presence of `revert_reason` depends on `execution_status`, +/// allowing more idiomatic access to `revert_reason`. #[derive(Debug, Clone, PartialEq, Eq)] pub enum ExecutionResult { + /// The execution succeeded. Succeeded, - Reverted { reason: String }, + /// The execution reverted. + Reverted { + /// The reason that the execution was reverted. + reason: String, + }, } impl ExecutionResult { + /// Gets the [`TransactionExecutionStatus`]. pub const fn status(&self) -> TransactionExecutionStatus { match self { Self::Succeeded => TransactionExecutionStatus::Succeeded, diff --git a/starknet-core/src/types/hash_256.rs b/starknet-core/src/types/hash_256.rs index b6ad9061..f47be680 100644 --- a/starknet-core/src/types/hash_256.rs +++ b/starknet-core/src/types/hash_256.rs @@ -9,6 +9,7 @@ use starknet_types_core::felt::Felt; const HASH_256_BYTE_COUNT: usize = 32; +/// A 256-bit cryptographic hash. #[derive(Clone, Copy, PartialEq, Eq)] pub struct Hash256 { inner: [u8; HASH_256_BYTE_COUNT], @@ -19,12 +20,16 @@ struct Hash256Visitor; mod errors { use core::fmt::{Display, Formatter, Result}; + /// Errors parsing [`Hash256`] from a hex string. #[derive(Debug)] pub enum FromHexError { + /// The hex string is not 64 hexadecimal characters in length without the `0x` prefix. UnexpectedLength, + /// The string contains non-hexadecimal characters. InvalidHexString, } + /// The hash value is out of range for converting into [`Felt`]. #[derive(Debug)] pub struct ToFieldElementError; @@ -56,18 +61,22 @@ mod errors { pub use errors::{FromHexError, ToFieldElementError}; impl Hash256 { + /// Constructs [`Hash256`] from a byte array. pub const fn from_bytes(bytes: [u8; HASH_256_BYTE_COUNT]) -> Self { Self { inner: bytes } } + /// Parses [`Hash256`] from a hex string. pub fn from_hex(hex: &str) -> Result { hex.parse() } + /// Constructs [`Hash256`] from a [`Felt`]. pub fn from_felt(felt: &Felt) -> Self { felt.into() } + /// Gets a reference to the underlying byte array. pub const fn as_bytes(&self) -> &[u8; HASH_256_BYTE_COUNT] { &self.inner } diff --git a/starknet-core/src/types/mod.rs b/starknet-core/src/types/mod.rs index 0d5321f8..3e7756b4 100644 --- a/starknet-core/src/types/mod.rs +++ b/starknet-core/src/types/mod.rs @@ -41,12 +41,15 @@ pub use codegen::{ TransactionReceiptWithBlockInfo, TransactionTraceWithHash, TransactionWithReceipt, }; +/// Module containing the [`U256`] type. pub mod u256; pub use u256::U256; +/// Module containing the [`EthAddress`] type. pub mod eth_address; pub use eth_address::EthAddress; +/// Module containing the [`Hash256`] type. pub mod hash_256; pub use hash_256::Hash256; @@ -60,53 +63,85 @@ mod msg; pub use msg::MsgToL2; // TODO: move generated request code to `starknet-providers` +/// Module containing JSON-RPC request types. pub mod requests; +/// Module containing types related to Starknet contracts/classes. pub mod contract; pub use contract::ContractArtifact; +/// A block with transaction hashes that may or may not be pending. +/// +/// A pending block lacks certain information on the block header compared to a non-pending block. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(untagged)] pub enum MaybePendingBlockWithTxHashes { + /// A confirmed, non-pending block. Block(BlockWithTxHashes), + /// A pending block. PendingBlock(PendingBlockWithTxHashes), } +/// A block with full transactions that may or may not be pending. +/// +/// A pending block lacks certain information on the block header compared to a non-pending block. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(untagged)] pub enum MaybePendingBlockWithTxs { + /// A confirmed, non-pending block. Block(BlockWithTxs), + /// A pending block. PendingBlock(PendingBlockWithTxs), } +/// A block with full transactions and receipts that may or may not be pending. +/// +/// A pending block lacks certain information on the block header compared to a non-pending block. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(untagged)] pub enum MaybePendingBlockWithReceipts { + /// A confirmed, non-pending block. Block(BlockWithReceipts), + /// A pending block. PendingBlock(PendingBlockWithReceipts), } +/// State update of a block that may or may not be pending. +/// +/// State update for a pending block lacks certain information compared to that of a non-pending +/// block. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(untagged)] pub enum MaybePendingStateUpdate { + /// The state update is for a confirmed, non-pending block. Update(StateUpdate), + /// The state update is for a pending block. PendingUpdate(PendingStateUpdate), } +/// The hash and number (height) for a block. #[serde_as] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct BlockHashAndNumber { + /// The block's hash. #[serde_as(as = "UfeHex")] pub block_hash: Felt, + /// The block's number (height). pub block_number: u64, } +/// A Starknet client node's synchronization status. #[derive(Debug, Clone, PartialEq, Eq)] pub enum SyncStatusType { + /// The node is synchronizing. Syncing(SyncStatus), + /// The node is not synchronizing. NotSyncing, } +/// A "page" of events in a cursor-based pagniation system. +/// +/// This type is usually returned from the `starknet_getEvents` RPC method. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct EventsPage { /// Matching events @@ -118,6 +153,7 @@ pub struct EventsPage { pub continuation_token: Option, } +/// Response for broadcasting an `INVOKE` transaction. #[serde_as] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct InvokeTransactionResult { @@ -126,6 +162,7 @@ pub struct InvokeTransactionResult { pub transaction_hash: Felt, } +/// Response for broadcasting a `DECLARE` transaction. #[serde_as] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct DeclareTransactionResult { @@ -137,6 +174,10 @@ pub struct DeclareTransactionResult { pub class_hash: Felt, } +/// Response for broadcasting a `DEPLOY` transaction. +/// +/// Note that `DEPLOY` transactions have been deprecated and disabled on all public Starknet +/// networks. #[serde_as] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct DeployTransactionResult { @@ -148,6 +189,7 @@ pub struct DeployTransactionResult { pub contract_address: Felt, } +/// Response for broadcasting a `DEPLOY_ACCOUNT` transaction. #[serde_as] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct DeployAccountTransactionResult { @@ -159,18 +201,25 @@ pub struct DeployAccountTransactionResult { pub contract_address: Felt, } -/// Block hash, number or tag +/// Block identifier in the form of hash, number or tag. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BlockId { + /// Block hash. Hash(Felt), + /// Block number (height). Number(u64), + /// Block tag. Tag(BlockTag), } +/// A "processed" contract class representation that's circulated in the network. This is different +/// from the class representation of compiler output. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(untagged)] pub enum ContractClass { + /// A "processed" Sierra (Cairo 1) class. Sierra(FlattenedSierraClass), + /// A "processed" legacy (Cairo 0) class. Legacy(CompressedLegacyContractClass), } @@ -209,136 +258,189 @@ impl TransactionStatus { } } +/// A Starknet transaction. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(tag = "type")] pub enum Transaction { + /// An `INVOKE` transaction. #[serde(rename = "INVOKE")] Invoke(InvokeTransaction), + /// An `L1_HANDLER` transaction. #[serde(rename = "L1_HANDLER")] L1Handler(L1HandlerTransaction), + /// A `DECLARE` transaction. #[serde(rename = "DECLARE")] Declare(DeclareTransaction), + /// A `DEPLOY` transaction. #[serde(rename = "DEPLOY")] Deploy(DeployTransaction), + /// A `DEPLOY_ACCOUNT` transaction. #[serde(rename = "DEPLOY_ACCOUNT")] DeployAccount(DeployAccountTransaction), } +/// A Starknet transaction in its "mempool" representation that's broadcast by a client. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(tag = "type")] pub enum BroadcastedTransaction { + /// An `INVOKE` transaction. #[serde(rename = "INVOKE")] Invoke(BroadcastedInvokeTransaction), + /// A `DECLARE` transaction. #[serde(rename = "DECLARE")] Declare(BroadcastedDeclareTransaction), + /// A `DEPLOY_ACCOUNT` transaction. #[serde(rename = "DEPLOY_ACCOUNT")] DeployAccount(BroadcastedDeployAccountTransaction), } +/// An `INVOKE` Starknet transaction. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(tag = "version")] pub enum InvokeTransaction { + /// Version 0 `INVOKE` transaction. #[serde(rename = "0x0")] V0(InvokeTransactionV0), + /// Version 1 `INVOKE` transaction. #[serde(rename = "0x1")] V1(InvokeTransactionV1), + /// Version 3 `INVOKE` transaction. #[serde(rename = "0x3")] V3(InvokeTransactionV3), } +/// A `DECLARE` Starknet transaction. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(tag = "version")] pub enum DeclareTransaction { + /// Version 0 `DECLARE` transaction. #[serde(rename = "0x0")] V0(DeclareTransactionV0), + /// Version 1 `DECLARE` transaction. #[serde(rename = "0x1")] V1(DeclareTransactionV1), + /// Version 2 `DECLARE` transaction. #[serde(rename = "0x2")] V2(DeclareTransactionV2), + /// Version 3 `DECLARE` transaction. #[serde(rename = "0x3")] V3(DeclareTransactionV3), } +/// A `DEPLOY_ACCOUNT` Starknet transaction. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(tag = "version")] pub enum DeployAccountTransaction { + /// Version 1 `DEPLOY_ACCOUNT` transaction. #[serde(rename = "0x1")] V1(DeployAccountTransactionV1), + /// Version 3 `DEPLOY_ACCOUNT` transaction. #[serde(rename = "0x3")] V3(DeployAccountTransactionV3), } +/// An `INVOKE` Starknet transaction in its "mempool" representation. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(untagged)] pub enum BroadcastedInvokeTransaction { + /// Version 1 `INVOKE` transaction. V1(BroadcastedInvokeTransactionV1), + /// Version 3 `INVOKE` transaction. V3(BroadcastedInvokeTransactionV3), } +/// A `DECLARE` Starknet transaction in its "mempool" representation. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(untagged)] pub enum BroadcastedDeclareTransaction { + /// Version 1 `DECLARE` transaction. V1(BroadcastedDeclareTransactionV1), + /// Version 2 `DECLARE` transaction. V2(BroadcastedDeclareTransactionV2), + /// Version 3 `DECLARE` transaction. V3(BroadcastedDeclareTransactionV3), } +/// A `DEPLOY_ACCOUNT` Starknet transaction in its "mempool" representation. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(untagged)] pub enum BroadcastedDeployAccountTransaction { + /// Version 1 `DEPLOY_ACCOUNT` transaction. V1(BroadcastedDeployAccountTransactionV1), + /// Version 3 `DEPLOY_ACCOUNT` transaction. V3(BroadcastedDeployAccountTransactionV3), } +/// Starknet transaction receipt containing execution results. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(tag = "type")] pub enum TransactionReceipt { + /// Receipt for an `INVOKE` transaction. #[serde(rename = "INVOKE")] Invoke(InvokeTransactionReceipt), + /// Receipt for an `L1_HANDLER` transaction. #[serde(rename = "L1_HANDLER")] L1Handler(L1HandlerTransactionReceipt), + /// Receipt for a `DECLARE` transaction. #[serde(rename = "DECLARE")] Declare(DeclareTransactionReceipt), + /// Receipt for a `DEPLOY` transaction. #[serde(rename = "DEPLOY")] Deploy(DeployTransactionReceipt), + /// Receipt for a `DEPLOY_ACCOUNT` transaction. #[serde(rename = "DEPLOY_ACCOUNT")] DeployAccount(DeployAccountTransactionReceipt), } +/// ABI entry item for legacy (Cairo 0) contract classes. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(untagged)] pub enum LegacyContractAbiEntry { + /// ABI entry representing a Cairo function. Function(LegacyFunctionAbiEntry), + /// ABI entry representing a Starknet event. Event(LegacyEventAbiEntry), + /// ABI entry representing a Cairo struct. Struct(LegacyStructAbiEntry), } +/// Execution trace of a Starknet transaction. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(tag = "type")] pub enum TransactionTrace { + /// Trace for an `INVOKE` transaction. #[serde(rename = "INVOKE")] Invoke(InvokeTransactionTrace), + /// Trace for a `DEPLOY_ACCOUNT` transaction. #[serde(rename = "DEPLOY_ACCOUNT")] DeployAccount(DeployAccountTransactionTrace), + /// Trace for an `L1_HANDLER` transaction. #[serde(rename = "L1_HANDLER")] L1Handler(L1HandlerTransactionTrace), + /// Trace for a `DECLARE` transaction. #[serde(rename = "DECLARE")] Declare(DeclareTransactionTrace), } +/// The execution result of a function invocation. #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(untagged)] pub enum ExecuteInvocation { + /// Successful invocation. Success(FunctionInvocation), + /// Failed and reverted invocation. Reverted(RevertedInvocation), } mod errors { use core::fmt::{Display, Formatter, Result}; + /// Errors parsing an L1-to-L2 message from transaction calldata. #[derive(Debug, PartialEq, Eq)] pub enum ParseMsgToL2Error { + /// The transaction calldata is empty. EmptyCalldata, + /// The L1 sender address is longer than 20 bytes. FromAddressOutOfRange, } @@ -364,6 +466,7 @@ mod errors { pub use errors::ParseMsgToL2Error; impl MaybePendingBlockWithTxHashes { + /// Gets a reference to the list of transaction hashes. pub fn transactions(&self) -> &[Felt] { match self { Self::Block(block) => &block.transactions, @@ -371,6 +474,7 @@ impl MaybePendingBlockWithTxHashes { } } + /// Gets a reference to the L1 gas price. pub const fn l1_gas_price(&self) -> &ResourcePrice { match self { Self::Block(block) => &block.l1_gas_price, @@ -380,6 +484,7 @@ impl MaybePendingBlockWithTxHashes { } impl MaybePendingBlockWithTxs { + /// Gets a reference to the list of transactions. pub fn transactions(&self) -> &[Transaction] { match self { Self::Block(block) => &block.transactions, @@ -387,6 +492,7 @@ impl MaybePendingBlockWithTxs { } } + /// Gets a reference to the L1 gas price. pub const fn l1_gas_price(&self) -> &ResourcePrice { match self { Self::Block(block) => &block.l1_gas_price, @@ -396,6 +502,7 @@ impl MaybePendingBlockWithTxs { } impl MaybePendingBlockWithReceipts { + /// Gets a reference to the list of transactions with receipts. pub fn transactions(&self) -> &[TransactionWithReceipt] { match self { Self::Block(block) => &block.transactions, @@ -403,6 +510,7 @@ impl MaybePendingBlockWithReceipts { } } + /// Gets a reference to the L1 gas price. pub const fn l1_gas_price(&self) -> &ResourcePrice { match self { Self::Block(block) => &block.l1_gas_price, @@ -412,6 +520,7 @@ impl MaybePendingBlockWithReceipts { } impl TransactionStatus { + /// Gets a reference to the transaction's finality status. pub const fn finality_status(&self) -> SequencerTransactionStatus { match self { Self::Received => SequencerTransactionStatus::Received, @@ -423,6 +532,7 @@ impl TransactionStatus { } impl Transaction { + /// Gets a reference to the transaction's hash. pub const fn transaction_hash(&self) -> &Felt { match self { Self::Invoke(tx) => tx.transaction_hash(), @@ -435,6 +545,7 @@ impl Transaction { } impl InvokeTransaction { + /// Gets a reference to the transaction's hash. pub const fn transaction_hash(&self) -> &Felt { match self { Self::V0(tx) => &tx.transaction_hash, @@ -445,6 +556,7 @@ impl InvokeTransaction { } impl DeclareTransaction { + /// Gets a reference to the transaction's hash. pub const fn transaction_hash(&self) -> &Felt { match self { Self::V0(tx) => &tx.transaction_hash, @@ -456,6 +568,7 @@ impl DeclareTransaction { } impl DeployAccountTransaction { + /// Gets a reference to the transaction's hash. pub const fn transaction_hash(&self) -> &Felt { match self { Self::V1(tx) => &tx.transaction_hash, @@ -465,6 +578,7 @@ impl DeployAccountTransaction { } impl TransactionReceipt { + /// Gets a reference to the transaction's hash. pub const fn transaction_hash(&self) -> &Felt { match self { Self::Invoke(receipt) => &receipt.transaction_hash, @@ -475,6 +589,7 @@ impl TransactionReceipt { } } + /// Gets a reference to the transaction's finality status. pub const fn finality_status(&self) -> &TransactionFinalityStatus { match self { Self::Invoke(receipt) => &receipt.finality_status, @@ -485,6 +600,7 @@ impl TransactionReceipt { } } + /// Gets a reference to the transaction's execution result. pub const fn execution_result(&self) -> &ExecutionResult { match self { Self::Invoke(receipt) => &receipt.execution_result, @@ -497,6 +613,8 @@ impl TransactionReceipt { } impl L1HandlerTransaction { + /// Parses [`MsgToL2`] from the transaction's calldata. This should not never fail on a genuine + /// `L1_HANDLER` transaction. pub fn parse_msg_to_l2(&self) -> Result { self.calldata.split_first().map_or( Err(ParseMsgToL2Error::EmptyCalldata), diff --git a/starknet-core/src/types/msg.rs b/starknet-core/src/types/msg.rs index c34919e9..beec076a 100644 --- a/starknet-core/src/types/msg.rs +++ b/starknet-core/src/types/msg.rs @@ -5,12 +5,18 @@ use starknet_types_core::felt::Felt; use super::{EthAddress, Hash256, MsgToL1}; +/// An L1-to-L2 message sent from Ethereum to Starknet. #[derive(Debug, Clone)] pub struct MsgToL2 { + /// The Ethereum address sending the message. pub from_address: EthAddress, + /// The Starknet contract address that handles the message. pub to_address: Felt, + /// The entrypoint selector on the handler contract. pub selector: Felt, + /// The calldata to be used for the handler contract invocation. pub payload: Vec, + /// The nonce on the message for duduplication. pub nonce: u64, } diff --git a/starknet-core/src/types/receipt_block.rs b/starknet-core/src/types/receipt_block.rs index a6216dfe..62e611f2 100644 --- a/starknet-core/src/types/receipt_block.rs +++ b/starknet-core/src/types/receipt_block.rs @@ -4,11 +4,22 @@ use serde_with::serde_as; use crate::serde::unsigned_field_element::UfeHex; use starknet_types_core::felt::Felt; -/// A more idiomatic way to access `execution_status` and `revert_reason`. +/// Block identifier used in [`TransactionReceiptWithBlockInfo`]. +/// +/// Instead of directly exposing the `block_hash` and `block_number` fields as [`Option`], +/// this struct captures the fact that these fields are always [`Some`](Option::Some) or +/// [`None`](Option::None) toggether, allowing idiomatic access without unnecessary unwraps. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ReceiptBlock { + /// The receipt is attached to a pending block. Pending, - Block { block_hash: Felt, block_number: u64 }, + /// The receipt is attached to a confirmed, non-pending block. + Block { + /// Block hash. + block_hash: Felt, + /// Block number (height). + block_number: u64, + }, } impl ReceiptBlock { diff --git a/starknet-core/src/types/u256.rs b/starknet-core/src/types/u256.rs index f02b87c0..fe57e728 100644 --- a/starknet-core/src/types/u256.rs +++ b/starknet-core/src/types/u256.rs @@ -11,35 +11,41 @@ use crate::types::Felt; pub struct U256(crypto_bigint::U256); impl U256 { - #[cfg(target_pointer_width = "64")] + /// Constructs a [U256] from the low 128 bits and the high 128 bits, similar to how they're + /// represented in Cairo. pub const fn from_words(low: u128, high: u128) -> Self { - Self(crypto_bigint::U256::from_words([ - low as u64, - (low >> 64) as u64, - high as u64, - (high >> 64) as u64, - ])) - } + #[cfg(target_pointer_width = "64")] + { + Self(crypto_bigint::U256::from_words([ + low as u64, + (low >> 64) as u64, + high as u64, + (high >> 64) as u64, + ])) + } - #[cfg(target_pointer_width = "32")] - pub const fn from_words(low: u128, high: u128) -> Self { - Self(crypto_bigint::U256::from_words([ - low as u32, - (low >> 32) as u32, - (low >> 64) as u32, - (low >> 96) as u32, - high as u32, - (high >> 32) as u32, - (high >> 64) as u32, - (high >> 96) as u32, - ])) + #[cfg(target_pointer_width = "32")] + { + Self(crypto_bigint::U256::from_words([ + low as u32, + (low >> 32) as u32, + (low >> 64) as u32, + (low >> 96) as u32, + high as u32, + (high >> 32) as u32, + (high >> 64) as u32, + (high >> 96) as u32, + ])) + } } + /// Gets the lower (least significant) 128 bits as [u128]. pub const fn low(&self) -> u128 { let words = u256_to_u64_array(&self.0); words[0] as u128 + ((words[1] as u128) << 64) } + /// Gets the higher (most significant) 128 bits as [u128]. pub const fn high(&self) -> u128 { let words = u256_to_u64_array(&self.0); words[2] as u128 + ((words[3] as u128) << 64) diff --git a/starknet-core/src/utils.rs b/starknet-core/src/utils.rs index 10bac139..00da1135 100644 --- a/starknet-core/src/utils.rs +++ b/starknet-core/src/utils.rs @@ -29,31 +29,46 @@ const CONTRACT_ADDRESS_PREFIX: Felt = Felt::from_raw([ /// The uniqueness settings for UDC deployments. #[derive(Debug, Clone)] pub enum UdcUniqueness { + /// Contract deployment is not unique to the deployer, as in any deployer account can deploy to + /// this same deployed address given the same settings. NotUnique, + /// Contract deployment is unique to the deployer, as in the deployer address is used to form + /// part of the deployment salt, making it impossible to another deployer account to deploy to + /// the same deployed address, even using the same UDC inputs. Unique(UdcUniqueSettings), } +/// The uniqueness settings when using [`UdcUniqueness::Unique`] for contract deployment. #[derive(Debug, Clone)] pub struct UdcUniqueSettings { + /// Contract address of the deployer account, which is the caller of the UDC. pub deployer_address: Felt, + /// The UDC address. pub udc_contract_address: Felt, } mod errors { use core::fmt::{Display, Formatter, Result}; + /// The string provided contains non-ASCII characters. #[derive(Debug)] pub struct NonAsciiNameError; + /// Possible errors for encoding a Cairo short string. #[derive(Debug)] pub enum CairoShortStringToFeltError { + /// The string provided contains non-ASCII characters. NonAsciiCharacter, + /// The string provided is longer than 31 characters. StringTooLong, } + /// Possible errors for decoding a Cairo short string. #[derive(Debug)] pub enum ParseCairoShortStringError { + /// The encoded [`Felt`] value is out of range. ValueOutOfRange, + /// A null terminator (`0x00`) is encountered. UnexpectedNullTerminator, } @@ -96,7 +111,8 @@ mod errors { } pub use errors::{CairoShortStringToFeltError, NonAsciiNameError, ParseCairoShortStringError}; -/// A variant of eth-keccak that computes a value that fits in a Starknet field element. +/// A variant of eth-keccak that computes a value that fits in a Starknet field element. It performs +/// a standard Keccak-256 but with the 6 most significant bits removed. pub fn starknet_keccak(data: &[u8]) -> Felt { let mut hasher = Keccak256::new(); hasher.update(data); @@ -109,6 +125,11 @@ pub fn starknet_keccak(data: &[u8]) -> Felt { Felt::from_bytes_be(unsafe { &*(hash[..].as_ptr() as *const [u8; 32]) }) } +/// Calculates the entrypoint selector from a human-readable function name. +/// +/// Returns the [Starknet Keccak](fn.starknet_keccak) of the function name in most cases, except for +/// 2 special built-in default entrypoints of `__default__` and `__l1_default__` for which `0` is +/// returned instead. pub fn get_selector_from_name(func_name: &str) -> Result { if func_name == DEFAULT_ENTRY_POINT_NAME || func_name == DEFAULT_L1_ENTRY_POINT_NAME { Ok(Felt::ZERO) @@ -122,6 +143,11 @@ pub fn get_selector_from_name(func_name: &str) -> Result Result { let var_name_bytes = var_name.as_bytes(); if var_name_bytes.is_ascii() { @@ -178,8 +204,13 @@ pub fn parse_cairo_short_string(felt: &Felt) -> Result Felt { address.mod_floor(&ADDR_BOUND) } From 3a5537a7f13d648a0dbd4c7ae6c11c3a19f77c91 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 29 Jul 2024 09:49:56 +0800 Subject: [PATCH 24/54] docs: fix broken links and add CI (#637) --- .github/workflows/doc.yml | 27 +++++++++++++++++++ examples/starknet-cxx/starknet-cxx/src/lib.rs | 2 +- starknet-core/src/serde/mod.rs | 2 +- starknet-core/src/types/eth_address.rs | 7 ++--- starknet-core/src/types/hash_256.rs | 4 +-- starknet-core/src/types/receipt_block.rs | 3 ++- starknet-core/src/utils.rs | 2 +- .../src/jsonrpc/transports/http.rs | 2 +- starknet-providers/src/provider.rs | 4 +-- starknet-providers/src/sequencer/mod.rs | 12 +++++---- 10 files changed, 48 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/doc.yml diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml new file mode 100644 index 00000000..0069c07a --- /dev/null +++ b/.github/workflows/doc.yml @@ -0,0 +1,27 @@ +on: + push: + branches: + - "master" + pull_request: + +name: "Build documentation" + +jobs: + build-doc: + name: "Build documentation" + runs-on: "ubuntu-latest" + + steps: + - name: "Checkout source code" + uses: "actions/checkout@v3" + + - name: "Setup stable toolchain" + uses: "actions-rs/toolchain@v1" + with: + toolchain: "stable" + profile: "minimal" + override: true + + - name: "Build docs" + run: | + RUSTDOCFLAGS="-D warnings -A rustdoc::missing-crate-level-docs" cargo doc --all diff --git a/examples/starknet-cxx/starknet-cxx/src/lib.rs b/examples/starknet-cxx/starknet-cxx/src/lib.rs index f34221b5..2bce3874 100644 --- a/examples/starknet-cxx/starknet-cxx/src/lib.rs +++ b/examples/starknet-cxx/starknet-cxx/src/lib.rs @@ -1,5 +1,5 @@ //! This is a quick demo on exposing `starknet-crypto` to C++ with the cxx bridge: -//! https://github.com/xJonathanLEI/starknet-rs/issues/325 +//! //! //! This wrapper crate expose functions that operate on strings, which is bad and probably hurts //! performance. It's possible to make the C++ side create `Felt` instances and operate on diff --git a/starknet-core/src/serde/mod.rs b/starknet-core/src/serde/mod.rs index abe1d561..0a7c8022 100644 --- a/starknet-core/src/serde/mod.rs +++ b/starknet-core/src/serde/mod.rs @@ -1,7 +1,7 @@ /// Custom serialization/deserialization implementations for [`Vec`]. pub mod byte_array; -/// Custom serialization/deserialization implementations for [`Felt`]. +/// Custom serialization/deserialization implementations for [`Felt`](crate::types::Felt). pub mod unsigned_field_element; pub(crate) mod num_hex; diff --git a/starknet-core/src/types/eth_address.rs b/starknet-core/src/types/eth_address.rs index fccda237..ab81606f 100644 --- a/starknet-core/src/types/eth_address.rs +++ b/starknet-core/src/types/eth_address.rs @@ -23,7 +23,7 @@ struct EthAddressVisitor; mod errors { use core::fmt::{Display, Formatter, Result}; - /// Errors parsing [`EthAddress`] from a hex string. + /// Errors parsing [`EthAddress`](super::EthAddress) from a hex string. #[derive(Debug)] pub enum FromHexError { /// The hex string is not 40 hexadecimal characters in length without the `0x` prefix. @@ -32,11 +32,12 @@ mod errors { InvalidHexString, } - /// The [`Felt`] value is out of range for converting into [`EthAddress`]. + /// The [`Felt`](super::Felt) value is out of range for converting into + /// [`EthAddress`](super::EthAddress). #[derive(Debug)] pub struct FromFieldElementError; - /// The byte slice is out of range for converting into [`EthAddress`]. + /// The byte slice is out of range for converting into [`EthAddress`](super::EthAddress). #[derive(Debug)] pub struct FromBytesSliceError; diff --git a/starknet-core/src/types/hash_256.rs b/starknet-core/src/types/hash_256.rs index f47be680..475e9b41 100644 --- a/starknet-core/src/types/hash_256.rs +++ b/starknet-core/src/types/hash_256.rs @@ -20,7 +20,7 @@ struct Hash256Visitor; mod errors { use core::fmt::{Display, Formatter, Result}; - /// Errors parsing [`Hash256`] from a hex string. + /// Errors parsing [`Hash256`](super::Hash256) from a hex string. #[derive(Debug)] pub enum FromHexError { /// The hex string is not 64 hexadecimal characters in length without the `0x` prefix. @@ -29,7 +29,7 @@ mod errors { InvalidHexString, } - /// The hash value is out of range for converting into [`Felt`]. + /// The hash value is out of range for converting into [`Felt`](super::Felt). #[derive(Debug)] pub struct ToFieldElementError; diff --git a/starknet-core/src/types/receipt_block.rs b/starknet-core/src/types/receipt_block.rs index 62e611f2..d9bc02bc 100644 --- a/starknet-core/src/types/receipt_block.rs +++ b/starknet-core/src/types/receipt_block.rs @@ -4,7 +4,8 @@ use serde_with::serde_as; use crate::serde::unsigned_field_element::UfeHex; use starknet_types_core::felt::Felt; -/// Block identifier used in [`TransactionReceiptWithBlockInfo`]. +/// Block identifier used in +/// [`TransactionReceiptWithBlockInfo`](super::TransactionReceiptWithBlockInfo). /// /// Instead of directly exposing the `block_hash` and `block_number` fields as [`Option`], /// this struct captures the fact that these fields are always [`Some`](Option::Some) or diff --git a/starknet-core/src/utils.rs b/starknet-core/src/utils.rs index 00da1135..36ec3d43 100644 --- a/starknet-core/src/utils.rs +++ b/starknet-core/src/utils.rs @@ -66,7 +66,7 @@ mod errors { /// Possible errors for decoding a Cairo short string. #[derive(Debug)] pub enum ParseCairoShortStringError { - /// The encoded [`Felt`] value is out of range. + /// The encoded [`Felt`](super::Felt) value is out of range. ValueOutOfRange, /// A null terminator (`0x00`) is encountered. UnexpectedNullTerminator, diff --git a/starknet-providers/src/jsonrpc/transports/http.rs b/starknet-providers/src/jsonrpc/transports/http.rs index f50bb46a..d8cd0576 100644 --- a/starknet-providers/src/jsonrpc/transports/http.rs +++ b/starknet-providers/src/jsonrpc/transports/http.rs @@ -41,7 +41,7 @@ impl HttpTransport { } /// Consumes the current [`HttpTransport`] instance and returns a new one with the header - /// appended. Same as calling [`add_header`]. + /// appended. Same as calling [`add_header`](fn.add_header). pub fn with_header(self, name: String, value: String) -> Self { let mut headers = self.headers; headers.push((name, value)); diff --git a/starknet-providers/src/provider.rs b/starknet-providers/src/provider.rs index 1d0588da..9259c855 100644 --- a/starknet-providers/src/provider.rs +++ b/starknet-providers/src/provider.rs @@ -247,7 +247,7 @@ pub trait Provider { where B: AsRef + Send + Sync; - /// Same as [estimate_fee], but only with one estimate. + /// Same as [`estimate_fee`](fn.estimate_fee), but only with one estimate. async fn estimate_fee_single( &self, request: R, @@ -271,7 +271,7 @@ pub trait Provider { } } - /// Same as [simulate_transactions], but only with one simulation. + /// Same as [`simulate_transactions`](fn.simulate_transactions), but only with one simulation. async fn simulate_transaction( &self, block_id: B, diff --git a/starknet-providers/src/sequencer/mod.rs b/starknet-providers/src/sequencer/mod.rs index b12c91e8..233a6eae 100644 --- a/starknet-providers/src/sequencer/mod.rs +++ b/starknet-providers/src/sequencer/mod.rs @@ -40,16 +40,18 @@ pub enum GatewayClientError { /// Sequencer error responses not parsable into [`StarknetError`] #[error(transparent)] SequencerError(SequencerError), - /// Method is not supported (only when using as [Provider]) + /// Method is not supported (only when using as [`Provider`](crate::Provider)) #[error("method not supported")] MethodNotSupported, - /// Model conversion error (only when using as [Provider]) + /// Model conversion error (only when using as [`Provider`](crate::Provider)) #[error("unable to convert gateway models to jsonrpc types")] ModelConversionError, - /// Simulating multiple transactions is not supported (only when using as [Provider]) + /// Simulating multiple transactions is not supported (only when using as + /// [`Provider`](crate::Provider)) #[error("simulating multiple transactions not supported")] BulkSimulationNotSupported, - /// At least one of the simulation flags is not supported (only when using as [Provider]) + /// At least one of the simulation flags is not supported (only when using as + /// [`Provider`](crate::Provider)) #[error("unsupported simulation flag")] UnsupportedSimulationFlag, } @@ -140,7 +142,7 @@ impl SequencerGatewayProvider { } /// Consumes the current [`SequencerGatewayProvider`] instance and returns a new one with the - /// header appended. Same as calling [`add_header`]. + /// header appended. Same as calling [`add_header`](fn.add_header). pub fn with_header(self, name: String, value: String) -> Self { let mut headers = self.headers; headers.push((name, value)); From 47265350e262805059b92389ad5015d5e8379dec Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 29 Jul 2024 13:37:55 +0800 Subject: [PATCH 25/54] docs: add docs for `starknet-signers` (#638) --- starknet-signers/src/key_pair.rs | 14 ++++++++++++++ starknet-signers/src/ledger.rs | 13 ++++++++++++- starknet-signers/src/lib.rs | 8 ++++++++ starknet-signers/src/local_wallet.rs | 5 +++++ starknet-signers/src/signer.rs | 14 ++++++++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/starknet-signers/src/key_pair.rs b/starknet-signers/src/key_pair.rs index 65047f20..2b24798e 100644 --- a/starknet-signers/src/key_pair.rs +++ b/starknet-signers/src/key_pair.rs @@ -6,23 +6,29 @@ use starknet_core::{ }; use starknet_crypto::get_public_key; +/// A ECDSA signing (private) key on the STARK curve. #[derive(Debug, Clone)] pub struct SigningKey { secret_scalar: Felt, } +/// A ECDSA verifying (public) key on the STARK curve. #[derive(Debug, Clone)] pub struct VerifyingKey { scalar: Felt, } +/// Errors using an encrypted JSON keystore. #[cfg(not(target_arch = "wasm32"))] #[derive(Debug, thiserror::Error)] pub enum KeystoreError { + /// The file path is invalid. #[error("invalid path")] InvalidPath, + /// The decrypted secret scalar is not a valid private key. #[error("invalid decrypted secret scalar")] InvalidScalar, + /// Upstream `eth-keystore` error propagated. #[error(transparent)] Inner(eth_keystore::KeystoreError), } @@ -47,6 +53,7 @@ impl SigningKey { Self { secret_scalar } } + /// Constructs [`SigningKey`] directly from a secret scalar. pub const fn from_secret_scalar(secret_scalar: Felt) -> Self { Self { secret_scalar } } @@ -92,28 +99,35 @@ impl SigningKey { Ok(()) } + /// Gets the secret scalar in the signing key. pub const fn secret_scalar(&self) -> Felt { self.secret_scalar } + /// Derives the verifying (public) key that corresponds to the signing key. pub fn verifying_key(&self) -> VerifyingKey { VerifyingKey::from_scalar(get_public_key(&self.secret_scalar)) } + /// Signs a raw hash using ECDSA for a signature. pub fn sign(&self, hash: &Felt) -> Result { ecdsa_sign(&self.secret_scalar, hash).map(|sig| sig.into()) } } impl VerifyingKey { + /// Constructs [`VerifyingKey`] directly from a scalar. pub const fn from_scalar(scalar: Felt) -> Self { Self { scalar } } + /// Gets the scalar in the verifying key. pub const fn scalar(&self) -> Felt { self.scalar } + /// Verifies that an ECDSA signature is valid for the verifying key against a certain message + /// hash. pub fn verify(&self, hash: &Felt, signature: &Signature) -> Result { ecdsa_verify(&self.scalar, hash, signature) } diff --git a/starknet-signers/src/ledger.rs b/starknet-signers/src/ledger.rs index e86ae90d..fd139b06 100644 --- a/starknet-signers/src/ledger.rs +++ b/starknet-signers/src/ledger.rs @@ -37,18 +37,29 @@ pub struct LedgerStarknetApp { transport: Ledger, } +/// Errors using the Ledger hardware wallet. #[derive(Debug, thiserror::Error)] pub enum LedgerError { + /// The HD wallet derivation path is malformed or does not conform to EIP-2645. #[error("derivation path is empty, not prefixed with m/2645', or is not 6-level long")] InvalidDerivationPath, + /// Error communicating with the Ledger hardware device. #[error(transparent)] TransportError(coins_ledger::LedgerError), + /// An unknown response code is returned from the device. #[error("unknown response code from Ledger: {0}")] UnknownResponseCode(u16), + /// The response code returned from the device does not indicate success. #[error("failed Ledger request: {0}")] UnsuccessfulRequest(APDUResponseCodes), + /// The response has an unexpected size. #[error("unexpected response length - expected: {expected}; actual: {actual}")] - UnexpectedResponseLength { expected: usize, actual: usize }, + UnexpectedResponseLength { + /// The expected response size. + expected: usize, + /// The actual response size. + actual: usize, + }, } /// The `GetPubKey` Ledger command. diff --git a/starknet-signers/src/lib.rs b/starknet-signers/src/lib.rs index 50903fab..59f9d292 100644 --- a/starknet-signers/src/lib.rs +++ b/starknet-signers/src/lib.rs @@ -1,3 +1,7 @@ +//! Starknet signer interface and common implementations. + +#![deny(missing_docs)] + mod key_pair; pub use key_pair::{SigningKey, VerifyingKey}; @@ -7,13 +11,17 @@ pub use key_pair::KeystoreError; mod signer; pub use signer::Signer; +/// Module containing types related to the use of a simple in-memory signer. pub mod local_wallet; pub use local_wallet::LocalWallet; +/// Module containing types related to the Ledger hardware wallet. #[cfg(feature = "ledger")] pub mod ledger; #[cfg(feature = "ledger")] pub use ledger::{DerivationPath, LedgerError, LedgerSigner}; +/// An error type that indicates an error cannot possibly occur. Used as placeholder where +/// [`Result`] is expected. #[derive(Debug, thiserror::Error)] pub enum Infallible {} diff --git a/starknet-signers/src/local_wallet.rs b/starknet-signers/src/local_wallet.rs index 2c898da0..0ad14c61 100644 --- a/starknet-signers/src/local_wallet.rs +++ b/starknet-signers/src/local_wallet.rs @@ -6,18 +6,23 @@ use starknet_core::{ types::Felt, }; +/// A signer that simply holds the signing (private) key in memory for performing cryptographic +/// operations. It's recommended to use hardware-based signers for use cases involving real value. #[derive(Debug, Clone)] pub struct LocalWallet { private_key: SigningKey, } +/// Errors using [`LocalWallet`]. #[derive(Debug, thiserror::Error)] pub enum SignError { + /// ECDSA signature error. #[error(transparent)] EcdsaSignError(EcdsaSignError), } impl LocalWallet { + /// Constructs [`LocalWallet`] from a [`SigningKey`]. pub fn from_signing_key(key: SigningKey) -> Self { key.into() } diff --git a/starknet-signers/src/signer.rs b/starknet-signers/src/signer.rs index 429efede..2a7d3a46 100644 --- a/starknet-signers/src/signer.rs +++ b/starknet-signers/src/signer.rs @@ -5,15 +5,29 @@ use auto_impl::auto_impl; use starknet_core::{crypto::Signature, types::Felt}; use std::error::Error; +/// Any signer that can provide a public key as [`Felt`], and sign a raw hash for a signature +/// encoded as [`Vec`]. #[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[auto_impl(&, Box, Arc)] pub trait Signer { + /// Possible errors for calling [`get_public_key`](fn.get_public_key). type GetPublicKeyError: Error + Send + Sync; + /// Possible errors for calling [`sign`](fn.sign). type SignError: Error + Send + Sync; + /// Retrieves the verifying (public) key from the signer. async fn get_public_key(&self) -> Result; + /// Requests an ECDSA signature for a message hash. + /// + /// Signing a raw hash is known as "blind signing". For interactive signers (e.g. hardware + /// wallets) that can theoretically provide better security properties via "clear signing", + /// using blind signing is bad practice. + /// + /// However, as of this writing, no actual interactive signer implementation offers clear + /// signing. When this changes in the future, this trait shall be altered to allow such clear + /// signing capabilities. async fn sign_hash(&self, hash: &Felt) -> Result; /// Whether the underlying signer implementation is interactive, such as a hardware wallet. From d297f8140e1fcd2862e5cdb60bdb915c8d7708d2 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 29 Jul 2024 14:34:35 +0800 Subject: [PATCH 26/54] docs: add docs for `starknet-providers` (#639) --- starknet-providers/src/any.rs | 2 + starknet-providers/src/jsonrpc/mod.rs | 103 +++++++++++++++++- .../src/jsonrpc/transports/http.rs | 9 ++ .../src/jsonrpc/transports/mod.rs | 4 + starknet-providers/src/lib.rs | 12 +- starknet-providers/src/provider.rs | 98 +++++++++++------ 6 files changed, 190 insertions(+), 38 deletions(-) diff --git a/starknet-providers/src/any.rs b/starknet-providers/src/any.rs index beff9c47..5a10711f 100644 --- a/starknet-providers/src/any.rs +++ b/starknet-providers/src/any.rs @@ -26,7 +26,9 @@ use crate::{ /// it's still needed anymore. #[derive(Debug)] pub enum AnyProvider { + /// JSON-RPC provider. JsonRpcHttp(JsonRpcClient), + /// Sequencer gateway provider. SequencerGateway(SequencerGatewayProvider), } diff --git a/starknet-providers/src/jsonrpc/mod.rs b/starknet-providers/src/jsonrpc/mod.rs index be9b9571..2d6013ed 100644 --- a/starknet-providers/src/jsonrpc/mod.rs +++ b/starknet-providers/src/jsonrpc/mod.rs @@ -24,144 +24,242 @@ use crate::{provider::ProviderImplError, Provider, ProviderError}; mod transports; pub use transports::{HttpTransport, HttpTransportError, JsonRpcTransport}; +/// A generic JSON-RPC client with any transport. +/// +/// A "transport" is any implementation that can send JSON-RPC requests and receive responses. This +/// most commonly happens over a network via HTTP connections, as with [`HttpTransport`]. #[derive(Debug)] pub struct JsonRpcClient { transport: T, } +/// All JSON-RPC methods as listed by the official specification. #[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub enum JsonRpcMethod { + /// The `starknet_specVersion` method. #[serde(rename = "starknet_specVersion")] SpecVersion, + /// The `starknet_getBlockWithTxHashes` method. #[serde(rename = "starknet_getBlockWithTxHashes")] GetBlockWithTxHashes, + /// The `starknet_getBlockWithTxs` method. #[serde(rename = "starknet_getBlockWithTxs")] GetBlockWithTxs, + /// The `starknet_getBlockWithReceipts` method. #[serde(rename = "starknet_getBlockWithReceipts")] GetBlockWithReceipts, + /// The `starknet_getStateUpdate` method. #[serde(rename = "starknet_getStateUpdate")] GetStateUpdate, + /// The `starknet_getStorageAt` method. #[serde(rename = "starknet_getStorageAt")] GetStorageAt, + /// The `starknet_getTransactionStatus` method. #[serde(rename = "starknet_getTransactionStatus")] GetTransactionStatus, + /// The `starknet_getTransactionByHash` method. #[serde(rename = "starknet_getTransactionByHash")] GetTransactionByHash, + /// The `starknet_getTransactionByBlockIdAndIndex` method. #[serde(rename = "starknet_getTransactionByBlockIdAndIndex")] GetTransactionByBlockIdAndIndex, + /// The `starknet_getTransactionReceipt` method. #[serde(rename = "starknet_getTransactionReceipt")] GetTransactionReceipt, + /// The `starknet_getClass` method. #[serde(rename = "starknet_getClass")] GetClass, + /// The `starknet_getClassHashAt` method. #[serde(rename = "starknet_getClassHashAt")] GetClassHashAt, + /// The `starknet_getClassAt` method. #[serde(rename = "starknet_getClassAt")] GetClassAt, + /// The `starknet_getBlockTransactionCount` method. #[serde(rename = "starknet_getBlockTransactionCount")] GetBlockTransactionCount, + /// The `starknet_call` method. #[serde(rename = "starknet_call")] Call, + /// The `starknet_estimateFee` method. #[serde(rename = "starknet_estimateFee")] EstimateFee, + /// The `starknet_estimateMessageFee` method. #[serde(rename = "starknet_estimateMessageFee")] EstimateMessageFee, + /// The `starknet_blockNumber` method. #[serde(rename = "starknet_blockNumber")] BlockNumber, + /// The `starknet_blockHashAndNumber` method. #[serde(rename = "starknet_blockHashAndNumber")] BlockHashAndNumber, + /// The `starknet_chainId` method. #[serde(rename = "starknet_chainId")] ChainId, + /// The `starknet_syncing` method. #[serde(rename = "starknet_syncing")] Syncing, + /// The `starknet_getEvents` method. #[serde(rename = "starknet_getEvents")] GetEvents, + /// The `starknet_getNonce` method. #[serde(rename = "starknet_getNonce")] GetNonce, + /// The `starknet_addInvokeTransaction` method. #[serde(rename = "starknet_addInvokeTransaction")] AddInvokeTransaction, + /// The `starknet_addDeclareTransaction` method. #[serde(rename = "starknet_addDeclareTransaction")] AddDeclareTransaction, + /// The `starknet_addDeployAccountTransaction` method. #[serde(rename = "starknet_addDeployAccountTransaction")] AddDeployAccountTransaction, + /// The `starknet_traceTransaction` method. #[serde(rename = "starknet_traceTransaction")] TraceTransaction, + /// The `starknet_simulateTransactions` method. #[serde(rename = "starknet_simulateTransactions")] SimulateTransactions, + /// The `starknet_traceBlockTransactions` method. #[serde(rename = "starknet_traceBlockTransactions")] TraceBlockTransactions, } +/// JSON-RPC request. #[derive(Debug, Clone)] pub struct JsonRpcRequest { + /// ID of the request. Useful for identifying responses in certain transports like `WebSocket`. pub id: u64, + /// Data of the requeest. pub data: JsonRpcRequestData, } +/// Typed request data for Starknet JSON-RPC requests. #[derive(Debug, Clone)] pub enum JsonRpcRequestData { + /// Request data for `starknet_specVersion`. SpecVersion(SpecVersionRequest), + /// Request data for `starknet_getBlockWithTxHashes`. GetBlockWithTxHashes(GetBlockWithTxHashesRequest), + /// Request data for `starknet_getBlockWithTxs`. GetBlockWithTxs(GetBlockWithTxsRequest), + /// Request data for `starknet_getBlockWithReceipts`. GetBlockWithReceipts(GetBlockWithReceiptsRequest), + /// Request data for `starknet_getStateUpdate`. GetStateUpdate(GetStateUpdateRequest), + /// Request data for `starknet_getStorageAt`. GetStorageAt(GetStorageAtRequest), + /// Request data for `starknet_getTransactionStatus`. GetTransactionStatus(GetTransactionStatusRequest), + /// Request data for `starknet_getTransactionByHash`. GetTransactionByHash(GetTransactionByHashRequest), + /// Request data for `starknet_getTransactionByBlockIdAndIndex`. GetTransactionByBlockIdAndIndex(GetTransactionByBlockIdAndIndexRequest), + /// Request data for `starknet_getTransactionReceipt`. GetTransactionReceipt(GetTransactionReceiptRequest), + /// Request data for `starknet_getClass`. GetClass(GetClassRequest), + /// Request data for `starknet_getClassHashAt`. GetClassHashAt(GetClassHashAtRequest), + /// Request data for `starknet_getClassAt`. GetClassAt(GetClassAtRequest), + /// Request data for `starknet_getBlockTransactionCount`. GetBlockTransactionCount(GetBlockTransactionCountRequest), + /// Request data for `starknet_call`. Call(CallRequest), + /// Request data for `starknet_estimateFee`. EstimateFee(EstimateFeeRequest), + /// Request data for `starknet_estimateMessageFee`. EstimateMessageFee(EstimateMessageFeeRequest), + /// Request data for `starknet_blockNumber`. BlockNumber(BlockNumberRequest), + /// Request data for `starknet_blockHashAndNumber`. BlockHashAndNumber(BlockHashAndNumberRequest), + /// Request data for `starknet_chainId`. ChainId(ChainIdRequest), + /// Request data for `starknet_syncing`. Syncing(SyncingRequest), + /// Request data for `starknet_getEvents`. GetEvents(GetEventsRequest), + /// Request data for `starknet_getNonce`. GetNonce(GetNonceRequest), + /// Request data for `starknet_addInvokeTransaction`. AddInvokeTransaction(AddInvokeTransactionRequest), + /// Request data for `starknet_addDeclareTransaction`. AddDeclareTransaction(AddDeclareTransactionRequest), + /// Request data for `starknet_addDeployAccountTransaction`. AddDeployAccountTransaction(AddDeployAccountTransactionRequest), + /// Request data for `starknet_traceTransaction`. TraceTransaction(TraceTransactionRequest), + /// Request data for `starknet_simulateTransactions`. SimulateTransactions(SimulateTransactionsRequest), + /// Request data for `starknet_traceBlockTransactions`. TraceBlockTransactions(TraceBlockTransactionsRequest), } +/// Errors from JSON-RPC client. #[derive(Debug, thiserror::Error)] pub enum JsonRpcClientError { + /// JSON serialization/deserialization erors. #[error(transparent)] JsonError(serde_json::Error), + /// Transport-specific errors. #[error(transparent)] TransportError(T), + /// An unsuccessful response returned from the server is encountered. #[error(transparent)] JsonRpcError(JsonRpcError), } +/// An unsuccessful response returned from the server. #[derive(Debug, Deserialize)] pub struct JsonRpcError { + /// Error code. pub code: i64, + /// Error message. pub message: String, + /// Additional error data if any. #[serde(skip_serializing_if = "Option::is_none")] pub data: Option, } +/// JSON-RPC response returned from a server. #[derive(Debug, Deserialize)] #[serde(untagged)] pub enum JsonRpcResponse { - Success { id: u64, result: T }, - Error { id: u64, error: JsonRpcError }, + /// Successful response. + Success { + /// Same ID as the corresponding request. + id: u64, + /// Response data. + result: T, + }, + /// Unsuccessful response. + Error { + /// Same ID as the corresponding request. + id: u64, + /// Error details. + error: JsonRpcError, + }, } /// Failures trying to parse a [`JsonRpcError`] into [`StarknetError`]. +/// +/// [`StarknetError`] is the standard, provider-agnostic error type that all [`Provider`] +/// implementations should strive to return in an error case, in a best-effort basis. This allows +/// for unified error handling logic. +/// +/// However, not all error cases can be properly converted, and this error type represents the cases +/// when such failure happens. #[derive(Debug, thiserror::Error)] pub enum JsonRpcErrorConversionError { + /// The error code is outside of the range specified by the specification. #[error("unknown error code")] UnknownCode, + /// Error data is expected but missing. #[error("missing data field")] MissingData, + /// Error data is malformed. #[error("unable to parse the data field")] DataParsingFailure, } @@ -175,6 +273,7 @@ struct Felt(#[serde_as(as = "UfeHex")] pub FeltPrimitive); struct FeltArray(#[serde_as(as = "Vec")] pub Vec); impl JsonRpcClient { + /// Constructs a new [`JsonRpcClient`] from a transport. pub const fn new(transport: T) -> Self { Self { transport } } diff --git a/starknet-providers/src/jsonrpc/transports/http.rs b/starknet-providers/src/jsonrpc/transports/http.rs index d8cd0576..4663b859 100644 --- a/starknet-providers/src/jsonrpc/transports/http.rs +++ b/starknet-providers/src/jsonrpc/transports/http.rs @@ -5,6 +5,7 @@ use serde::{de::DeserializeOwned, Serialize}; use crate::jsonrpc::{transports::JsonRpcTransport, JsonRpcMethod, JsonRpcResponse}; +/// A [`JsonRpcTransport`] implementation that uses HTTP connections. #[derive(Debug)] pub struct HttpTransport { client: Client, @@ -12,10 +13,13 @@ pub struct HttpTransport { headers: Vec<(String, String)>, } +/// Errors using [`HttpTransport`]. #[derive(Debug, thiserror::Error)] #[error(transparent)] pub enum HttpTransportError { + /// HTTP-related errors. Reqwest(reqwest::Error), + /// JSON serialization/deserialization errors. Json(serde_json::Error), } @@ -28,10 +32,15 @@ struct JsonRpcRequest { } impl HttpTransport { + /// Constructs [`HttpTransport`] from a JSON-RPC server URL, using default HTTP client settings. + /// + /// To use custom HTTP settings (e.g. proxy, timeout), use + /// [`new_with_client`](fn.new_with_client) instead. pub fn new(url: impl Into) -> Self { Self::new_with_client(url, Client::new()) } + /// Constructs [`HttpTransport`] from a JSON-RPC server URL and a custom `reqwest` client. pub fn new_with_client(url: impl Into, client: Client) -> Self { Self { client, diff --git a/starknet-providers/src/jsonrpc/transports/mod.rs b/starknet-providers/src/jsonrpc/transports/mod.rs index 7b119f74..c7602c98 100644 --- a/starknet-providers/src/jsonrpc/transports/mod.rs +++ b/starknet-providers/src/jsonrpc/transports/mod.rs @@ -8,12 +8,16 @@ use crate::jsonrpc::{JsonRpcMethod, JsonRpcResponse}; mod http; pub use http::{HttpTransport, HttpTransportError}; +/// Any type that is capable of producing JSON-RPC responses when given JSON-RPC requests. An +/// implementation does not necessarily use the network, but typically does. #[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[auto_impl(&, Box, Arc)] pub trait JsonRpcTransport { + /// Possible errors processing requests. type Error: Error + Send + Sync; + /// Sends a JSON-RPC request to retrieve a response. async fn send_request( &self, method: JsonRpcMethod, diff --git a/starknet-providers/src/lib.rs b/starknet-providers/src/lib.rs index 31dde2b2..0954c3d2 100644 --- a/starknet-providers/src/lib.rs +++ b/starknet-providers/src/lib.rs @@ -1,13 +1,23 @@ -#![doc = include_str!("../README.md")] +//! Clients for interacting with Starknet nodes and sequencers. +//! +//! This crate provides the [`Provider`] trait for abstraction over means of accessing the Starknet +//! network. The most commonly used implementation is [`JsonRpcClient`] with +//! [`HttpTransport`](jsonrpc::HttpTransport). + +#![deny(missing_docs)] mod provider; pub use provider::{Provider, ProviderError}; +// Sequencer-related functionalities are mostly deprecated so we skip the docs. +/// Module containing types related to the (now deprecated) sequencer gateway client. +#[allow(missing_docs)] pub mod sequencer; pub use sequencer::{ GatewayClientError as SequencerGatewayProviderError, SequencerGatewayProvider, }; +/// Module containing types related to JSON-RPC clients and servers. pub mod jsonrpc; pub use jsonrpc::JsonRpcClient; diff --git a/starknet-providers/src/provider.rs b/starknet-providers/src/provider.rs index 9259c855..94d853c3 100644 --- a/starknet-providers/src/provider.rs +++ b/starknet-providers/src/provider.rs @@ -12,14 +12,24 @@ use starknet_core::types::{ }; use std::{any::Any, error::Error, fmt::Debug}; +/// A generic interface for any type allowing communication with a Starknet network. +/// +/// Historically, the only official way to access the network is through the sequencer gateway, +/// implemented by [`SequencerGatewayProvider`](crate::sequencer::SequencerGatewayProvider), which +/// has since been deprecated. Currently, the recommended way of accessing the network is via the +/// JSON-RPC specification, implemented with [`JsonRpcClient`](crate::jsonrpc::JsonRpcClient). +/// +/// The legacy [`SequencerGatewayProvider`](crate::sequencer::SequencerGatewayProvider) still +/// implements this trait for backward compatibility reasons, but most of its methods no longer work +/// in practice, as public sequencer servers have generally block access to most methods. #[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[auto_impl(&, Box, Arc)] pub trait Provider { - /// Returns the version of the Starknet JSON-RPC specification being used + /// Returns the version of the Starknet JSON-RPC specification being used. async fn spec_version(&self) -> Result; - /// Get block information with transaction hashes given the block id + /// Gets block information with transaction hashes given the block id. async fn get_block_with_tx_hashes( &self, block_id: B, @@ -27,7 +37,7 @@ pub trait Provider { where B: AsRef + Send + Sync; - /// Get block information with full transactions given the block id + /// Gets block information with full transactions given the block id. async fn get_block_with_txs( &self, block_id: B, @@ -35,7 +45,7 @@ pub trait Provider { where B: AsRef + Send + Sync; - /// Get block information with full transactions and receipts given the block id + /// Gets block information with full transactions and receipts given the block id. async fn get_block_with_receipts( &self, block_id: B, @@ -43,7 +53,7 @@ pub trait Provider { where B: AsRef + Send + Sync; - /// Get the information about the result of executing the requested block + /// Gets the information about the result of executing the requested block. async fn get_state_update( &self, block_id: B, @@ -51,7 +61,7 @@ pub trait Provider { where B: AsRef + Send + Sync; - /// Get the value of the storage at the given address and key + /// Gets the value of the storage at the given address and key. async fn get_storage_at( &self, contract_address: A, @@ -63,8 +73,8 @@ pub trait Provider { K: AsRef + Send + Sync, B: AsRef + Send + Sync; - /// Gets the transaction status (possibly reflecting that the tx is still in - /// the mempool, or dropped from it) + /// Gets the transaction status (possibly reflecting that the tx is still in the mempool, or + /// dropped from it). async fn get_transaction_status( &self, transaction_hash: H, @@ -72,7 +82,7 @@ pub trait Provider { where H: AsRef + Send + Sync; - /// Get the details and status of a submitted transaction + /// Gets the details and status of a submitted transaction. async fn get_transaction_by_hash( &self, transaction_hash: H, @@ -80,7 +90,7 @@ pub trait Provider { where H: AsRef + Send + Sync; - /// Get the details of a transaction by a given block id and index + /// Gets the details of a transaction by a given block id and index. async fn get_transaction_by_block_id_and_index( &self, block_id: B, @@ -89,7 +99,7 @@ pub trait Provider { where B: AsRef + Send + Sync; - /// Get the details of a transaction by a given block number and index + /// Gets the details of a transaction by a given block number and index. async fn get_transaction_receipt( &self, transaction_hash: H, @@ -97,7 +107,7 @@ pub trait Provider { where H: AsRef + Send + Sync; - /// Get the contract class definition in the given block associated with the given hash + /// Gets the contract class definition in the given block associated with the given hash. async fn get_class( &self, block_id: B, @@ -107,7 +117,8 @@ pub trait Provider { B: AsRef + Send + Sync, H: AsRef + Send + Sync; - /// Get the contract class hash in the given block for the contract deployed at the given address + /// Gets the contract class hash in the given block for the contract deployed at the given + /// address. async fn get_class_hash_at( &self, block_id: B, @@ -117,7 +128,7 @@ pub trait Provider { B: AsRef + Send + Sync, A: AsRef + Send + Sync; - /// Get the contract class definition in the given block at the given address + /// Gets the contract class definition in the given block at the given address. async fn get_class_at( &self, block_id: B, @@ -127,18 +138,18 @@ pub trait Provider { B: AsRef + Send + Sync, A: AsRef + Send + Sync; - /// Get the number of transactions in a block given a block id + /// Gets the number of transactions in a block given a block id. async fn get_block_transaction_count(&self, block_id: B) -> Result where B: AsRef + Send + Sync; - /// Call a starknet function without creating a Starknet transaction + /// Calls a starknet function without creating a Starknet transaction. async fn call(&self, request: R, block_id: B) -> Result, ProviderError> where R: AsRef + Send + Sync, B: AsRef + Send + Sync; - /// Estimate the fee for a given Starknet transaction + /// Estimates the fee for a given Starknet transaction. async fn estimate_fee( &self, request: R, @@ -150,6 +161,7 @@ pub trait Provider { S: AsRef<[SimulationFlagForEstimateFee]> + Send + Sync, B: AsRef + Send + Sync; + /// Estimates the fee for sending an L1-to-L2 message. async fn estimate_message_fee( &self, message: M, @@ -159,19 +171,19 @@ pub trait Provider { M: AsRef + Send + Sync, B: AsRef + Send + Sync; - /// Get the most recent accepted block number + /// Gets the most recent accepted block number. async fn block_number(&self) -> Result; - /// Get the most recent accepted block hash and number + /// Gets the most recent accepted block hash and number. async fn block_hash_and_number(&self) -> Result; - /// Return the currently configured Starknet chain id + /// Returns the currently configured Starknet chain id. async fn chain_id(&self) -> Result; - /// Returns an object about the sync status, or false if the node is not synching + /// Returns an object about the sync status, or false if the node is not synching. async fn syncing(&self) -> Result; - /// Returns all events matching the given filter + /// Returns all events matching the given filter. async fn get_events( &self, filter: EventFilter, @@ -179,7 +191,7 @@ pub trait Provider { chunk_size: u64, ) -> Result; - /// Get the nonce associated with the given address in the given block + /// Gets the nonce associated with the given address in the given block. async fn get_nonce( &self, block_id: B, @@ -189,7 +201,7 @@ pub trait Provider { B: AsRef + Send + Sync, A: AsRef + Send + Sync; - /// Submit a new transaction to be added to the chain + /// Submits a new transaction to be added to the chain. async fn add_invoke_transaction( &self, invoke_transaction: I, @@ -197,7 +209,7 @@ pub trait Provider { where I: AsRef + Send + Sync; - /// Submit a new transaction to be added to the chain + /// Submits a new transaction to be added to the chain. async fn add_declare_transaction( &self, declare_transaction: D, @@ -205,7 +217,7 @@ pub trait Provider { where D: AsRef + Send + Sync; - /// Submit a new deploy account transaction + /// Submits a new deploy account transaction. async fn add_deploy_account_transaction( &self, deploy_account_transaction: D, @@ -213,8 +225,8 @@ pub trait Provider { where D: AsRef + Send + Sync; - /// For a given executed transaction, return the trace of its execution, including internal - /// calls + /// For a given executed transaction, returns the trace of its execution, including internal + /// calls. async fn trace_transaction( &self, transaction_hash: H, @@ -222,12 +234,13 @@ pub trait Provider { where H: AsRef + Send + Sync; - /// Simulate a given sequence of transactions on the requested state, and generate the execution - /// 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. + /// Simulates a given sequence of transactions on the requested state, and generate the + /// execution 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, @@ -239,7 +252,7 @@ pub trait Provider { T: AsRef<[BroadcastedTransaction]> + Send + Sync, S: AsRef<[SimulationFlag]> + Send + Sync; - /// Retrieve traces for all transactions in the given block. + /// Retrieves traces for all transactions in the given block. async fn trace_block_transactions( &self, block_id: B, @@ -311,14 +324,29 @@ pub trait ProviderImplError: Error + Debug + Send + Sync { fn as_any(&self) -> &dyn Any; } +/// Errors using any [`Provider`] implementation. This type is deliberately not made generic such +/// that: +/// +/// - the [`Provider`] trait itself can be boxed; +/// - error handling is easier. +/// +/// As a downside, the [`Other`](ProviderError::Other) variant contains a boxed implementation- +/// specific error. It's generally expected that users of [`Provider`] would not need to care about +/// these errors, but in the case where they do, it's slightly harder to access than if generics are +/// used instead. #[derive(Debug, thiserror::Error)] pub enum ProviderError { + /// A Starknet-related error, usually regarding the state or transaction. #[error(transparent)] StarknetError(StarknetError), + /// The request fails as the client is rate-limited. #[error("Request rate limited")] RateLimited, + /// When estimating fees for or simulating a single transaction, the server unexpectedly returns + /// data for zero or more than one transactions. #[error("Array length mismatch")] ArrayLengthMismatch, + /// Boxed implementation-specific errors. #[error("{0}")] Other(Box), } From 66ac385c74519e53c04273d7d99e85f52595465d Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 29 Jul 2024 16:28:10 +0800 Subject: [PATCH 27/54] docs: add docs for `starknet-accounts` (#640) --- starknet-accounts/src/account/declaration.rs | 61 ++++++++++ starknet-accounts/src/account/execution.rs | 41 +++++++ starknet-accounts/src/account/mod.rs | 105 +++++++++++++++++- starknet-accounts/src/call.rs | 4 + starknet-accounts/src/factory/argent.rs | 3 + starknet-accounts/src/factory/mod.rs | 78 ++++++++++++- .../src/factory/open_zeppelin.rs | 3 + starknet-accounts/src/lib.rs | 6 + starknet-accounts/src/single_owner.rs | 6 + 9 files changed, 303 insertions(+), 4 deletions(-) diff --git a/starknet-accounts/src/account/declaration.rs b/starknet-accounts/src/account/declaration.rs index d8d2de4e..8efe9b59 100644 --- a/starknet-accounts/src/account/declaration.rs +++ b/starknet-accounts/src/account/declaration.rs @@ -52,6 +52,10 @@ const QUERY_VERSION_THREE: Felt = Felt::from_raw([ ]); impl<'a, A> DeclarationV2<'a, A> { + /// Constructs a new [`DeclarationV2`]. + /// + /// Users would typically use [`declare_v2`](fn.declare_v2) on an [`Account`] instead of + /// directly calling this method. pub const fn new( contract_class: Arc, compiled_class_hash: Felt, @@ -67,6 +71,7 @@ impl<'a, A> DeclarationV2<'a, A> { } } + /// Returns a new [`DeclarationV2`] with the `nonce`. pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), @@ -74,6 +79,7 @@ impl<'a, A> DeclarationV2<'a, A> { } } + /// Returns a new [`DeclarationV2`] with the `max_fee`. pub fn max_fee(self, max_fee: Felt) -> Self { Self { max_fee: Some(max_fee), @@ -81,6 +87,9 @@ impl<'a, A> DeclarationV2<'a, A> { } } + /// Returns a new [`DeclarationV2`] with the fee estimate multiplier. The multiplier is used + /// when transaction fee is not manually specified and must be fetched from a [`Provider`] + /// instead. pub fn fee_estimate_multiplier(self, fee_estimate_multiplier: f64) -> Self { Self { fee_estimate_multiplier, @@ -110,6 +119,7 @@ impl<'a, A> DeclarationV2<'a, A> where A: ConnectedAccount + Sync, { + /// Estimates transaction fees from a [`Provider`]. pub async fn estimate_fee(&self) -> Result> { // Resolves nonce let nonce = match self.nonce { @@ -124,6 +134,8 @@ where self.estimate_fee_with_nonce(nonce).await } + /// Simulates the transaction from a [`Provider`]. Transaction validation and fee transfer can + /// be skipped. pub async fn simulate( &self, skip_validate: bool, @@ -143,6 +155,7 @@ where .await } + /// Signs and broadcasts the transaction to the network. pub async fn send(&self) -> Result> { self.prepare().await?.send().await } @@ -275,6 +288,10 @@ where } impl<'a, A> DeclarationV3<'a, A> { + /// Constructs a new [`DeclarationV3`]. + /// + /// Users would typically use [`declare_v3`](fn.declare_v3) on an [`Account`] instead of + /// directly calling this method. pub const fn new( contract_class: Arc, compiled_class_hash: Felt, @@ -292,6 +309,7 @@ impl<'a, A> DeclarationV3<'a, A> { } } + /// Returns a new [`DeclarationV3`] with the `nonce`. pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), @@ -299,6 +317,7 @@ impl<'a, A> DeclarationV3<'a, A> { } } + /// Returns a new [`DeclarationV3`] with the `gas`. pub fn gas(self, gas: u64) -> Self { Self { gas: Some(gas), @@ -306,6 +325,7 @@ impl<'a, A> DeclarationV3<'a, A> { } } + /// Returns a new [`DeclarationV3`] with the `gas_price`. pub fn gas_price(self, gas_price: u128) -> Self { Self { gas_price: Some(gas_price), @@ -313,6 +333,9 @@ impl<'a, A> DeclarationV3<'a, A> { } } + /// Returns a new [`DeclarationV3`] with the gas amount estimate multiplier. The multiplier is + /// used when the gas amount is not manually specified and must be fetched from a [`Provider`] + /// instead. pub fn gas_estimate_multiplier(self, gas_estimate_multiplier: f64) -> Self { Self { gas_estimate_multiplier, @@ -320,6 +343,9 @@ impl<'a, A> DeclarationV3<'a, A> { } } + /// Returns a new [`DeclarationV3`] with the gas price estimate multiplier. The multiplier is + /// used when the gas price is not manually specified and must be fetched from a [`Provider`] + /// instead. pub fn gas_price_estimate_multiplier(self, gas_price_estimate_multiplier: f64) -> Self { Self { gas_price_estimate_multiplier, @@ -351,6 +377,7 @@ impl<'a, A> DeclarationV3<'a, A> where A: ConnectedAccount + Sync, { + /// Estimates transaction fees from a [`Provider`]. pub async fn estimate_fee(&self) -> Result> { // Resolves nonce let nonce = match self.nonce { @@ -365,6 +392,8 @@ where self.estimate_fee_with_nonce(nonce).await } + /// Simulates the transaction from a [`Provider`]. Transaction validation and fee transfer can + /// be skipped. pub async fn simulate( &self, skip_validate: bool, @@ -384,6 +413,7 @@ where .await } + /// Signs and broadcasts the transaction to the network. pub async fn send(&self) -> Result> { self.prepare().await?.send().await } @@ -570,6 +600,10 @@ where } impl<'a, A> LegacyDeclaration<'a, A> { + /// Constructs a new [`LegacyDeclaration`]. + /// + /// Users would typically use [`declare_legacy`](fn.declare_legacy) on an [`Account`] instead of + /// directly calling this method. pub const fn new(contract_class: Arc, account: &'a A) -> Self { Self { account, @@ -580,6 +614,7 @@ impl<'a, A> LegacyDeclaration<'a, A> { } } + /// Returns a new [`LegacyDeclaration`] with the `nonce`. pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), @@ -587,6 +622,7 @@ impl<'a, A> LegacyDeclaration<'a, A> { } } + /// Returns a new [`LegacyDeclaration`] with the `max_fee`. pub fn max_fee(self, max_fee: Felt) -> Self { Self { max_fee: Some(max_fee), @@ -594,6 +630,9 @@ impl<'a, A> LegacyDeclaration<'a, A> { } } + /// Returns a new [`LegacyDeclaration`] with the fee estimate multiplier. The multiplier is used + /// when transaction fee is not manually specified and must be fetched from a [`Provider`] + /// instead. pub fn fee_estimate_multiplier(self, fee_estimate_multiplier: f64) -> Self { Self { fee_estimate_multiplier, @@ -623,6 +662,7 @@ impl<'a, A> LegacyDeclaration<'a, A> where A: ConnectedAccount + Sync, { + /// Estimates transaction fees from a [`Provider`]. pub async fn estimate_fee(&self) -> Result> { // Resolves nonce let nonce = match self.nonce { @@ -637,6 +677,8 @@ where self.estimate_fee_with_nonce(nonce).await } + /// Simulates the transaction from a [`Provider`]. Transaction validation and fee transfer can + /// be skipped. pub async fn simulate( &self, skip_validate: bool, @@ -656,6 +698,7 @@ where .await } + /// Signs and broadcasts the transaction to the network. pub async fn send(&self) -> Result> { self.prepare().await?.send().await } @@ -787,6 +830,7 @@ where } impl RawDeclarationV2 { + /// Calculates transaction hash given `chain_id`, `address`, and `query_only`. pub fn transaction_hash(&self, chain_id: Felt, address: Felt, query_only: bool) -> Felt { compute_hash_on_elements(&[ PREFIX_DECLARE, @@ -805,24 +849,29 @@ impl RawDeclarationV2 { ]) } + /// Gets a reference to the flattened Sierra (Cairo 1) class being declared. pub fn contract_class(&self) -> &FlattenedSierraClass { &self.contract_class } + /// Gets the CASM class hash corresponding to the Sierra class being declared. pub const fn compiled_class_hash(&self) -> Felt { self.compiled_class_hash } + /// Gets the `nonce` of the declaration request. pub const fn nonce(&self) -> Felt { self.nonce } + /// Gets the `max_fee` of the declaration request. pub const fn max_fee(&self) -> Felt { self.max_fee } } impl RawDeclarationV3 { + /// Calculates transaction hash given `chain_id`, `address`, and `query_only`. pub fn transaction_hash(&self, chain_id: Felt, address: Felt, query_only: bool) -> Felt { let mut hasher = PoseidonHasher::new(); @@ -876,28 +925,34 @@ impl RawDeclarationV3 { hasher.finalize() } + /// Gets a reference to the flattened Sierra (Cairo 1) class being declared. pub fn contract_class(&self) -> &FlattenedSierraClass { &self.contract_class } + /// Gets the CASM class hash corresponding to the Sierra class being declared. pub const fn compiled_class_hash(&self) -> Felt { self.compiled_class_hash } + /// Gets the `nonce` of the declaration request. pub const fn nonce(&self) -> Felt { self.nonce } + /// Gets the `gas` of the declaration request. pub const fn gas(&self) -> u64 { self.gas } + /// Gets the `gas_price` of the declaration request. pub const fn gas_price(&self) -> u128 { self.gas_price } } impl RawLegacyDeclaration { + /// Calculates transaction hash given `chain_id`, `address`, and `query_only`. pub fn transaction_hash( &self, chain_id: Felt, @@ -920,14 +975,17 @@ impl RawLegacyDeclaration { ])) } + /// Gets a reference to the legacy (Cairo 0) class being declared. pub fn contract_class(&self) -> &LegacyContractClass { &self.contract_class } + /// Gets the `nonce` of the declaration request. pub const fn nonce(&self) -> Felt { self.nonce } + /// Gets the `max_fee` of the declaration request. pub const fn max_fee(&self) -> Felt { self.max_fee } @@ -949,6 +1007,7 @@ impl<'a, A> PreparedDeclarationV2<'a, A> where A: ConnectedAccount, { + /// Signs and broadcasts the transaction to the network. pub async fn send(&self) -> Result> { let tx_request = self.get_declare_request(false, false).await?; self.account @@ -998,6 +1057,7 @@ impl<'a, A> PreparedDeclarationV3<'a, A> where A: ConnectedAccount, { + /// Signs and broadcasts the transaction to the network. pub async fn send(&self) -> Result> { let tx_request = self.get_declare_request(false, false).await?; self.account @@ -1066,6 +1126,7 @@ impl<'a, A> PreparedLegacyDeclaration<'a, A> where A: ConnectedAccount, { + /// Signs and broadcasts the transaction to the network. pub async fn send(&self) -> Result> { let tx_request = self.get_declare_request(false, false).await?; self.account diff --git a/starknet-accounts/src/account/execution.rs b/starknet-accounts/src/account/execution.rs index 3e529a45..b96ee505 100644 --- a/starknet-accounts/src/account/execution.rs +++ b/starknet-accounts/src/account/execution.rs @@ -41,6 +41,10 @@ const QUERY_VERSION_THREE: Felt = Felt::from_raw([ ]); impl<'a, A> ExecutionV1<'a, A> { + /// Constructs a new [`ExecutionV1`]. + /// + /// Users would typically use [`execute_v1`](fn.execute_v1) on an [`Account`] instead of + /// directly calling this method. pub const fn new(calls: Vec, account: &'a A) -> Self { Self { account, @@ -51,6 +55,7 @@ impl<'a, A> ExecutionV1<'a, A> { } } + /// Returns a new [`ExecutionV1`] with the `nonce`. pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), @@ -58,6 +63,7 @@ impl<'a, A> ExecutionV1<'a, A> { } } + /// Returns a new [`ExecutionV1`] with the `max_fee`. pub fn max_fee(self, max_fee: Felt) -> Self { Self { max_fee: Some(max_fee), @@ -65,6 +71,9 @@ impl<'a, A> ExecutionV1<'a, A> { } } + /// Returns a new [`ExecutionV1`] with the fee estimate multiplier. The multiplier is used + /// when transaction fee is not manually specified and must be fetched from a [`Provider`] + /// instead. pub fn fee_estimate_multiplier(self, fee_estimate_multiplier: f64) -> Self { Self { fee_estimate_multiplier, @@ -90,6 +99,10 @@ impl<'a, A> ExecutionV1<'a, A> { } impl<'a, A> ExecutionV3<'a, A> { + /// Constructs a new [`ExecutionV3`]. + /// + /// Users would typically use [`execute_v3`](fn.execute_v3) on an [`Account`] instead of + /// directly calling this method. pub const fn new(calls: Vec, account: &'a A) -> Self { Self { account, @@ -102,6 +115,7 @@ impl<'a, A> ExecutionV3<'a, A> { } } + /// Returns a new [`ExecutionV3`] with the `nonce`. pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), @@ -109,6 +123,7 @@ impl<'a, A> ExecutionV3<'a, A> { } } + /// Returns a new [`ExecutionV3`] with the `gas`. pub fn gas(self, gas: u64) -> Self { Self { gas: Some(gas), @@ -116,6 +131,7 @@ impl<'a, A> ExecutionV3<'a, A> { } } + /// Returns a new [`ExecutionV3`] with the `gas_price`. pub fn gas_price(self, gas_price: u128) -> Self { Self { gas_price: Some(gas_price), @@ -123,6 +139,9 @@ impl<'a, A> ExecutionV3<'a, A> { } } + /// Returns a new [`ExecutionV3`] with the gas amount estimate multiplier. The multiplier is + /// used when the gas amount is not manually specified and must be fetched from a [`Provider`] + /// instead. pub fn gas_estimate_multiplier(self, gas_estimate_multiplier: f64) -> Self { Self { gas_estimate_multiplier, @@ -130,6 +149,9 @@ impl<'a, A> ExecutionV3<'a, A> { } } + /// Returns a new [`ExecutionV3`] with the gas price estimate multiplier. The multiplier is + /// used when the gas price is not manually specified and must be fetched from a [`Provider`] + /// instead. pub fn gas_price_estimate_multiplier(self, gas_price_estimate_multiplier: f64) -> Self { Self { gas_price_estimate_multiplier, @@ -160,6 +182,7 @@ impl<'a, A> ExecutionV1<'a, A> where A: ConnectedAccount + Sync, { + /// Estimates transaction fees from a [`Provider`]. pub async fn estimate_fee(&self) -> Result> { // Resolves nonce let nonce = match self.nonce { @@ -174,6 +197,8 @@ where self.estimate_fee_with_nonce(nonce).await } + /// Simulates the transaction from a [`Provider`]. Transaction validation and fee transfer can + /// be skipped. pub async fn simulate( &self, skip_validate: bool, @@ -193,6 +218,7 @@ where .await } + /// Signs and broadcasts the transaction to the network. pub async fn send(&self) -> Result> { self.prepare().await?.send().await } @@ -331,6 +357,7 @@ impl<'a, A> ExecutionV3<'a, A> where A: ConnectedAccount + Sync, { + /// Estimates transaction fees from a [`Provider`]. pub async fn estimate_fee(&self) -> Result> { // Resolves nonce let nonce = match self.nonce { @@ -345,6 +372,8 @@ where self.estimate_fee_with_nonce(nonce).await } + /// Simulates the transaction from a [`Provider`]. Transaction validation and fee transfer can + /// be skipped. pub async fn simulate( &self, skip_validate: bool, @@ -364,6 +393,7 @@ where .await } + /// Signs and broadcasts the transaction to the network. pub async fn send(&self) -> Result> { self.prepare().await?.send().await } @@ -553,6 +583,7 @@ where } impl RawExecutionV1 { + /// Calculates transaction hash given `chain_id`, `address`, `query_only`, and `encoder`. pub fn transaction_hash( &self, chain_id: Felt, @@ -579,20 +610,24 @@ impl RawExecutionV1 { ]) } + /// Gets a reference to the list of contract calls included in the execution. pub fn calls(&self) -> &[Call] { &self.calls } + /// Gets the `nonce` of the execution request. pub const fn nonce(&self) -> Felt { self.nonce } + /// Gets the `max_fee` of the execution request. pub const fn max_fee(&self) -> Felt { self.max_fee } } impl RawExecutionV3 { + /// Calculates transaction hash given `chain_id`, `address`, `query_only`, and `encoder`. pub fn transaction_hash( &self, chain_id: Felt, @@ -663,18 +698,22 @@ impl RawExecutionV3 { hasher.finalize() } + /// Gets a reference to the list of contract calls included in the execution. pub fn calls(&self) -> &[Call] { &self.calls } + /// Gets the `nonce` of the execution request. pub const fn nonce(&self) -> Felt { self.nonce } + /// Gets the `gas` of the execution request. pub const fn gas(&self) -> u64 { self.gas } + /// Gets the `gas_price` of the execution request. pub const fn gas_price(&self) -> u128 { self.gas_price } @@ -716,6 +755,7 @@ impl<'a, A> PreparedExecutionV1<'a, A> where A: ConnectedAccount, { + /// Signs and broadcasts the transaction to the network. pub async fn send(&self) -> Result> { let tx_request = self .get_invoke_request(false, false) @@ -757,6 +797,7 @@ impl<'a, A> PreparedExecutionV3<'a, A> where A: ConnectedAccount, { + /// Signs and broadcasts the transaction to the network. pub async fn send(&self) -> Result> { let tx_request = self .get_invoke_request(false, false) diff --git a/starknet-accounts/src/account/mod.rs b/starknet-accounts/src/account/mod.rs index 5bb2db3e..a3e19f54 100644 --- a/starknet-accounts/src/account/mod.rs +++ b/starknet-accounts/src/account/mod.rs @@ -19,36 +19,64 @@ mod execution; #[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] pub trait Account: ExecutionEncoder + Sized { + /// Possible errors for signing transactions. type SignError: Error + Send + Sync; + /// Gets the account contract's address. fn address(&self) -> Felt; + /// Gets the chain ID of the network where the account contract was deployed. fn chain_id(&self) -> Felt; + /// Signs an execution request to authorize an `INVOKE` v1 transaction that pays transaction + /// fees in `ETH`. + /// + /// If `query_only` is `true`, the commitment must be constructed in a way that a real state- + /// changing transaction cannot be authenticated. This is to prevent replay attacks. async fn sign_execution_v1( &self, execution: &RawExecutionV1, query_only: bool, ) -> Result, Self::SignError>; + /// Signs an execution request to authorize an `INVOKE` v3 transaction that pays transaction + /// fees in `STRK`. + /// + /// If `query_only` is `true`, the commitment must be constructed in a way that a real state- + /// changing transaction cannot be authenticated. This is to prevent replay attacks. async fn sign_execution_v3( &self, execution: &RawExecutionV3, query_only: bool, ) -> Result, Self::SignError>; + /// Signs an execution request to authorize an `DECLARE` v2 transaction that pays transaction + /// fees in `ETH` for declaring Cairo 1 classes. + /// + /// If `query_only` is `true`, the commitment must be constructed in a way that a real state- + /// changing transaction cannot be authenticated. This is to prevent replay attacks. async fn sign_declaration_v2( &self, declaration: &RawDeclarationV2, query_only: bool, ) -> Result, Self::SignError>; + /// Signs an execution request to authorize an `DECLARE` v3 transaction that pays transaction + /// fees in `STRK` for declaring Cairo 1 classes. + /// + /// If `query_only` is `true`, the commitment must be constructed in a way that a real state- + /// changing transaction cannot be authenticated. This is to prevent replay attacks. async fn sign_declaration_v3( &self, declaration: &RawDeclarationV3, query_only: bool, ) -> Result, Self::SignError>; + /// Signs an execution request to authorize an `DECLARE` v1 transaction that pays transaction + /// fees in `ETH` for declaring Cairo 0 classes. + /// + /// If `query_only` is `true`, the commitment must be constructed in a way that a real state- + /// changing transaction cannot be authenticated. This is to prevent replay attacks. async fn sign_legacy_declaration( &self, legacy_declaration: &RawLegacyDeclaration, @@ -63,19 +91,40 @@ pub trait Account: ExecutionEncoder + Sized { /// estimation/simulation purposes. fn is_signer_interactive(&self) -> bool; + /// Generates an instance of [`ExecutionV1`] for sending `INVOKE` v1 transactions. Pays + /// transaction fees in `ETH`. fn execute_v1(&self, calls: Vec) -> ExecutionV1<'_, Self> { ExecutionV1::new(calls, self) } + /// Generates an instance of [`ExecutionV3`] for sending `INVOKE` v3 transactions. Pays + /// transaction fees in `STRK`. fn execute_v3(&self, calls: Vec) -> ExecutionV3<'_, Self> { ExecutionV3::new(calls, self) } + /// Generates an instance of [`ExecutionV1`] for sending `INVOKE` v1 transactions. Pays + /// transaction fees in `ETH`. #[deprecated = "use version specific variants (`execute_v1` & `execute_v3`) instead"] fn execute(&self, calls: Vec) -> ExecutionV1<'_, Self> { self.execute_v1(calls) } + /// Generates an instance of [`DeclarationV2`] for sending `DECLARE` v2 transactions. Pays + /// transaction fees in `ETH`. + /// + /// To declare a Sierra (Cairo 1) class, a `compiled_class_hash` must be provided. This can be + /// obtained by compiling the Sierra class to obtain a CASM class, and then hashing it. + /// + /// The compilation of Sierra to CASM can either be done interactively via the + /// `starknet-sierra-compile` command from the Cairo toolchain, or programmatically through the + /// Cairo crates. + /// + /// Hashing the resulting CASM class is supported in the `starknet-core` crate. It can also be + /// done interactively via Starkli with its `starkli class-hash` command. + /// + /// This method is only used for declaring Sierra (Cairo 1) classes. To declare legacy (Cairo 0) + /// classes use [`declare_legacy`](fn.declare_legacy) instead. fn declare_v2( &self, contract_class: Arc, @@ -84,6 +133,21 @@ pub trait Account: ExecutionEncoder + Sized { DeclarationV2::new(contract_class, compiled_class_hash, self) } + /// Generates an instance of [`DeclarationV3`] for sending `DECLARE` v3 transactions. Pays + /// transaction fees in `STRK`. + /// + /// To declare a Sierra (Cairo 1) class, a `compiled_class_hash` must be provided. This can be + /// obtained by compiling the Sierra class to obtain a CASM class, and then hashing it. + /// + /// The compilation of Sierra to CASM can either be done interactively via the + /// `starknet-sierra-compile` command from the Cairo toolchain, or programmatically through the + /// Cairo crates. + /// + /// Hashing the resulting CASM class is supported in the `starknet-core` crate. It can also be + /// done interactively via Starkli with its `starkli class-hash` command. + /// + /// This method is only used for declaring Sierra (Cairo 1) classes. To declare legacy (Cairo 0) + /// classes use [`declare_legacy`](fn.declare_legacy) instead. fn declare_v3( &self, contract_class: Arc, @@ -92,6 +156,21 @@ pub trait Account: ExecutionEncoder + Sized { DeclarationV3::new(contract_class, compiled_class_hash, self) } + /// Generates an instance of [`DeclarationV2`] for sending `DECLARE` v2 transactions. Pays + /// transaction fees in `ETH`. + /// + /// To declare a Sierra (Cairo 1) class, a `compiled_class_hash` must be provided. This can be + /// obtained by compiling the Sierra class to obtain a CASM class, and then hashing it. + /// + /// The compilation of Sierra to CASM can either be done interactively via the + /// `starknet-sierra-compile` command from the Cairo toolchain, or programmatically through the + /// Cairo crates. + /// + /// Hashing the resulting CASM class is supported in the `starknet-core` crate. It can also be + /// done interactively via Starkli with its `starkli class-hash` command. + /// + /// This method is only used for declaring Sierra (Cairo 1) classes. To declare legacy (Cairo 0) + /// classes use [`declare_legacy`](fn.declare_legacy) instead. #[deprecated = "use version specific variants (`declare_v2` & `declare_v3`) instead"] fn declare( &self, @@ -101,6 +180,11 @@ pub trait Account: ExecutionEncoder + Sized { self.declare_v2(contract_class, compiled_class_hash) } + /// Generates an instance of [`LegacyDeclaration`] for sending `DECLARE` v1 transactions. Pays + /// transaction fees in `ETH`. + /// + /// This method is only used for declaring legacy (Cairo 0) classes. To declare Sierra (Cairo 1) + /// classes use [`declare_v2`](fn.declare_v2) or [`declare_v3`](fn.declare_v3) instead. fn declare_legacy( &self, contract_class: Arc, @@ -109,26 +193,35 @@ pub trait Account: ExecutionEncoder + Sized { } } +/// An abstraction over different ways to encode [`Vec`] into [`Vec`]. +/// +/// Standard Cairo 0 and Cairo 1 account contracts encodes calls differently. Custom account +/// contract implementations might also impose arbitrary encoding rules. #[auto_impl(&, Box, Arc)] pub trait ExecutionEncoder { + /// Encodes the list of [`Call`] into a list of [`Felt`] to be used as calldata to the account's + /// `__execute__` entrypoint. fn encode_calls(&self, calls: &[Call]) -> Vec; } -/// An [Account] implementation that also comes with a [Provider]. Functionalities that require a -/// connection to the sequencer or node are offloaded to this trait to keep the base [Account] +/// An [`Account`] implementation that also comes with a [`Provider`]. Functionalities that require +/// a connection to the sequencer or node are offloaded to this trait to keep the base [`Account`] /// clean and flexible. #[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] pub trait ConnectedAccount: Account { + /// The [`Provider`] type attached to this account. type Provider: Provider + Sync; + /// Gets a reference to the attached [`Provider`] instance. fn provider(&self) -> &Self::Provider; - /// Block ID to use when checking nonce and estimating fees. + /// Gets block ID to use when checking nonce and estimating fees. fn block_id(&self) -> BlockId { BlockId::Tag(BlockTag::Latest) } + /// Gets the next available nonce to be used. async fn get_nonce(&self) -> Result { self.provider() .get_nonce(self.block_id(), self.address()) @@ -294,16 +387,22 @@ pub struct PreparedLegacyDeclaration<'a, A> { inner: RawLegacyDeclaration, } +/// Errors using Starknet accounts. #[derive(Debug, thiserror::Error)] pub enum AccountError { + /// An error is encountered when signing a request. #[error(transparent)] Signing(S), + /// An error is encountered with communicating with the network. #[error(transparent)] Provider(ProviderError), + /// Unable to calculate the class hash for declaration. #[error(transparent)] ClassHashCalculation(ComputeClassHashError), + /// Unable to compress the legacy (Cairo 0) class for declaration. #[error(transparent)] ClassCompression(CompressProgramError), + /// Transaction fee calculation overflow. #[error("fee calculation overflow")] FeeOutOfRange, } diff --git a/starknet-accounts/src/call.rs b/starknet-accounts/src/call.rs index 6d86ed53..0788e011 100644 --- a/starknet-accounts/src/call.rs +++ b/starknet-accounts/src/call.rs @@ -1,8 +1,12 @@ use starknet_core::types::Felt; +/// A contract call as part of a multi-call execution request. #[derive(Debug, Clone)] pub struct Call { + /// Address of the contract being invoked. pub to: Felt, + /// Entrypoint selector of the function being invoked. pub selector: Felt, + /// List of calldata to be sent for the call. pub calldata: Vec, } diff --git a/starknet-accounts/src/factory/argent.rs b/starknet-accounts/src/factory/argent.rs index a8cf6482..23bf3d7f 100644 --- a/starknet-accounts/src/factory/argent.rs +++ b/starknet-accounts/src/factory/argent.rs @@ -8,6 +8,7 @@ use starknet_core::types::{BlockId, BlockTag, Felt}; use starknet_providers::Provider; use starknet_signers::Signer; +/// [`AccountFactory`] implementation for deploying `Argent X` account contracts. #[derive(Debug)] pub struct ArgentAccountFactory { class_hash: Felt, @@ -23,6 +24,7 @@ impl ArgentAccountFactory where S: Signer, { + /// Constructs a new [`ArgentAccountFactory`]. pub async fn new( class_hash: Felt, chain_id: Felt, @@ -42,6 +44,7 @@ where }) } + /// Sets a new block ID to run queries against. pub fn set_block_id(&mut self, block_id: BlockId) -> &Self { self.block_id = block_id; self diff --git a/starknet-accounts/src/factory/mod.rs b/starknet-accounts/src/factory/mod.rs index 17f3d2a2..c72ab017 100644 --- a/starknet-accounts/src/factory/mod.rs +++ b/starknet-accounts/src/factory/mod.rs @@ -58,19 +58,26 @@ const ADDR_BOUND: NonZeroFelt = NonZeroFelt::from_raw([ 18446743986131443745, ]); -/// This trait enables deploying account contracts using the `DeployAccount` transaction type. +/// Abstraction over different ways of deploying account contracts using the `DEPLOY_ACCOUNT` +/// transaction type. #[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] pub trait AccountFactory: Sized { + /// The [`Provider`] type attached to this account factory. type Provider: Provider + Sync; + /// Possible errors for signing transactions. type SignError: Error + Send + Sync; + /// Gets the class hash of the account contract. fn class_hash(&self) -> Felt; + /// Gets the constructor calldata for the deployment transaction. fn calldata(&self) -> Vec; + /// Gets the chain ID of the target network. fn chain_id(&self) -> Felt; + /// Gets a reference to the attached [`Provider`] instance. fn provider(&self) -> &Self::Provider; /// Whether the underlying signer implementation is interactive, such as a hardware wallet. @@ -86,26 +93,42 @@ pub trait AccountFactory: Sized { BlockId::Tag(BlockTag::Latest) } + /// Signs an execution request to authorize an `DEPLOY_ACCOUNT` v1 transaction that pays + /// transaction fees in `ETH`. + /// + /// If `query_only` is `true`, the commitment must be constructed in a way that a real state- + /// changing transaction cannot be authenticated. This is to prevent replay attacks. async fn sign_deployment_v1( &self, deployment: &RawAccountDeploymentV1, query_only: bool, ) -> Result, Self::SignError>; + /// Signs an execution request to authorize an `DEPLOY_ACCOUNT` v3 transaction that pays + /// transaction fees in `STRK`. + /// + /// If `query_only` is `true`, the commitment must be constructed in a way that a real state- + /// changing transaction cannot be authenticated. This is to prevent replay attacks. async fn sign_deployment_v3( &self, deployment: &RawAccountDeploymentV3, query_only: bool, ) -> Result, Self::SignError>; + /// Generates an instance of [`AccountDeploymentV1`] for sending `DEPLOY_ACCOUNT` v1 + /// transactions. Pays transaction fees in `ETH`. fn deploy_v1(&self, salt: Felt) -> AccountDeploymentV1<'_, Self> { AccountDeploymentV1::new(salt, self) } + /// Generates an instance of [`AccountDeploymentV3`] for sending `DEPLOY_ACCOUNT` v3 + /// transactions. Pays transaction fees in `STRK`. fn deploy_v3(&self, salt: Felt) -> AccountDeploymentV3<'_, Self> { AccountDeploymentV3::new(salt, self) } + /// Generates an instance of [`AccountDeploymentV1`] for sending `DEPLOY_ACCOUNT` v1 + /// transactions. Pays transaction fees in `ETH`. #[deprecated = "use version specific variants (`deploy_v1` & `deploy_v3`) instead"] fn deploy(&self, salt: Felt) -> AccountDeploymentV1<'_, Self> { self.deploy_v1(salt) @@ -180,17 +203,25 @@ pub struct PreparedAccountDeploymentV3<'f, F> { inner: RawAccountDeploymentV3, } +/// Errors using Starknet account factories. #[derive(Debug, thiserror::Error)] pub enum AccountFactoryError { + /// An error is encountered when signing a request. #[error(transparent)] Signing(S), + /// An error is encountered with communicating with the network. #[error(transparent)] Provider(ProviderError), + /// Transaction fee calculation overflow. #[error("fee calculation overflow")] FeeOutOfRange, } impl<'f, F> AccountDeploymentV1<'f, F> { + /// Constructs a new [`AccountDeploymentV1`]. + /// + /// Users would typically use [`deploy_v1`](fn.deploy_v1) on an [`AccountFactory`] instead of + /// directly calling this method. pub const fn new(salt: Felt, factory: &'f F) -> Self { Self { factory, @@ -201,6 +232,7 @@ impl<'f, F> AccountDeploymentV1<'f, F> { } } + /// Returns a new [`AccountDeploymentV1`] with the `nonce`. pub const fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), @@ -208,6 +240,7 @@ impl<'f, F> AccountDeploymentV1<'f, F> { } } + /// Returns a new [`AccountDeploymentV1`] with the `max_fee`. pub const fn max_fee(self, max_fee: Felt) -> Self { Self { max_fee: Some(max_fee), @@ -215,6 +248,9 @@ impl<'f, F> AccountDeploymentV1<'f, F> { } } + /// Returns a new [`AccountDeploymentV1`] with the fee estimate multiplier. The multiplier is + /// used when transaction fee is not manually specified and must be fetched from a [`Provider`] + /// instead. pub const fn fee_estimate_multiplier(self, fee_estimate_multiplier: f64) -> Self { Self { fee_estimate_multiplier, @@ -241,6 +277,10 @@ impl<'f, F> AccountDeploymentV1<'f, F> { } impl<'f, F> AccountDeploymentV3<'f, F> { + /// Constructs a new [`AccountDeploymentV3`]. + /// + /// Users would typically use [`deploy_v3`](fn.deploy_v3) on an [`AccountFactory`] instead of + /// directly calling this method. pub const fn new(salt: Felt, factory: &'f F) -> Self { Self { factory, @@ -253,6 +293,7 @@ impl<'f, F> AccountDeploymentV3<'f, F> { } } + /// Returns a new [`AccountDeploymentV3`] with the `nonce`. pub const fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), @@ -260,6 +301,7 @@ impl<'f, F> AccountDeploymentV3<'f, F> { } } + /// Returns a new [`AccountDeploymentV3`] with the `gas`. pub const fn gas(self, gas: u64) -> Self { Self { gas: Some(gas), @@ -267,6 +309,7 @@ impl<'f, F> AccountDeploymentV3<'f, F> { } } + /// Returns a new [`AccountDeploymentV3`] with the `gas_price`. pub const fn gas_price(self, gas_price: u128) -> Self { Self { gas_price: Some(gas_price), @@ -274,6 +317,9 @@ impl<'f, F> AccountDeploymentV3<'f, F> { } } + /// Returns a new [`AccountDeploymentV3`] with the gas amount estimate multiplier. The + /// multiplier is used when the gas amount is not manually specified and must be fetched from a + /// [`Provider`] instead. pub const fn gas_estimate_multiplier(self, gas_estimate_multiplier: f64) -> Self { Self { gas_estimate_multiplier, @@ -281,6 +327,9 @@ impl<'f, F> AccountDeploymentV3<'f, F> { } } + /// Returns a new [`AccountDeploymentV3`] with the gas price estimate multiplier. The + /// multiplier is used when the gas price is not manually specified and must be fetched from a + /// [`Provider`] instead. pub const fn gas_price_estimate_multiplier(self, gas_price_estimate_multiplier: f64) -> Self { Self { gas_price_estimate_multiplier, @@ -321,6 +370,8 @@ where ) } + /// Fetches the next available nonce from a [`Provider`]. In most cases this would be `0` but + /// it can also be non-zero if previous reverted deployment attempts exist. pub async fn fetch_nonce(&self) -> Result { match self .factory @@ -334,6 +385,7 @@ where } } + /// Estimates transaction fees from a [`Provider`]. pub async fn estimate_fee(&self) -> Result> { // Resolves nonce let nonce = match self.nonce { @@ -347,6 +399,8 @@ where self.estimate_fee_with_nonce(nonce).await } + /// Simulates the transaction from a [`Provider`]. Transaction validation and fee transfer can + /// be skipped. pub async fn simulate( &self, skip_validate: bool, @@ -365,6 +419,7 @@ where .await } + /// Signs and broadcasts the transaction to the network. pub async fn send( &self, ) -> Result> { @@ -520,6 +575,8 @@ where ) } + /// Fetches the next available nonce from a [`Provider`]. In most cases this would be `0` but + /// it can also be non-zero if previous reverted deployment attempts exist. pub async fn fetch_nonce(&self) -> Result { match self .factory @@ -533,6 +590,7 @@ where } } + /// Estimates transaction fees from a [`Provider`]. pub async fn estimate_fee(&self) -> Result> { // Resolves nonce let nonce = match self.nonce { @@ -546,6 +604,8 @@ where self.estimate_fee_with_nonce(nonce).await } + /// Simulates the transaction from a [`Provider`]. Transaction validation and fee transfer can + /// be skipped. pub async fn simulate( &self, skip_validate: bool, @@ -564,6 +624,7 @@ where .await } + /// Signs and broadcasts the transaction to the network. pub async fn send( &self, ) -> Result> { @@ -760,38 +821,47 @@ where } impl RawAccountDeploymentV1 { + /// Gets the `salt` of the deployment request. pub const fn salt(&self) -> Felt { self.salt } + /// Gets the `nonce` of the deployment request. pub const fn nonce(&self) -> Felt { self.nonce } + /// Gets the `max_fee` of the deployment request. pub const fn max_fee(&self) -> Felt { self.max_fee } } impl RawAccountDeploymentV3 { + /// Gets the `salt` of the deployment request. pub const fn salt(&self) -> Felt { self.salt } + /// Gets the `nonce` of the deployment request. pub const fn nonce(&self) -> Felt { self.nonce } + /// Gets the `gas` of the deployment request. pub const fn gas(&self) -> u64 { self.gas } + /// Gets the `gas_price` of the deployment request. pub const fn gas_price(&self) -> u128 { self.gas_price } } impl<'f, F> PreparedAccountDeploymentV1<'f, F> { + /// Constructs [`PreparedAccountDeploymentV1`] by attaching a factory to + /// [`RawAccountDeploymentV1`]. pub const fn from_raw(raw_deployment: RawAccountDeploymentV1, factory: &'f F) -> Self { Self { factory, @@ -801,6 +871,8 @@ impl<'f, F> PreparedAccountDeploymentV1<'f, F> { } impl<'f, F> PreparedAccountDeploymentV3<'f, F> { + /// Constructs [`PreparedAccountDeploymentV3`] by attaching a factory to + /// [`RawAccountDeploymentV3`]. pub const fn from_raw(raw_deployment: RawAccountDeploymentV3, factory: &'f F) -> Self { Self { factory, @@ -822,6 +894,7 @@ where ) } + /// Calculates transaction hash given `query_only`. pub fn transaction_hash(&self, query_only: bool) -> Felt { let mut calldata_to_hash = vec![self.factory.class_hash(), self.inner.salt]; calldata_to_hash.append(&mut self.factory.calldata()); @@ -842,6 +915,7 @@ where ]) } + /// Signs and broadcasts the transaction to the network. pub async fn send( &self, ) -> Result> { @@ -892,6 +966,7 @@ where ) } + /// Calculates transaction hash given `query_only`. pub fn transaction_hash(&self, query_only: bool) -> Felt { let mut hasher = PoseidonHasher::new(); @@ -953,6 +1028,7 @@ where hasher.finalize() } + /// Signs and broadcasts the transaction to the network. pub async fn send( &self, ) -> Result> { diff --git a/starknet-accounts/src/factory/open_zeppelin.rs b/starknet-accounts/src/factory/open_zeppelin.rs index 8fa95022..90c32722 100644 --- a/starknet-accounts/src/factory/open_zeppelin.rs +++ b/starknet-accounts/src/factory/open_zeppelin.rs @@ -8,6 +8,7 @@ use starknet_core::types::{BlockId, BlockTag, Felt}; use starknet_providers::Provider; use starknet_signers::Signer; +/// [`AccountFactory`] implementation for deploying `OpenZeppelin` account contracts. #[derive(Debug)] pub struct OpenZeppelinAccountFactory { class_hash: Felt, @@ -22,6 +23,7 @@ impl OpenZeppelinAccountFactory where S: Signer, { + /// Constructs a new [`OpenZeppelinAccountFactory`]. pub async fn new( class_hash: Felt, chain_id: Felt, @@ -39,6 +41,7 @@ where }) } + /// Sets a new block ID to run queries against. pub fn set_block_id(&mut self, block_id: BlockId) -> &Self { self.block_id = block_id; self diff --git a/starknet-accounts/src/lib.rs b/starknet-accounts/src/lib.rs index b0f4483f..5da9d090 100644 --- a/starknet-accounts/src/lib.rs +++ b/starknet-accounts/src/lib.rs @@ -1,3 +1,7 @@ +//! Library for deploying and using Starknet account contracts. + +#![deny(missing_docs)] + mod account; pub use account::{ Account, AccountError, ConnectedAccount, DeclarationV2, DeclarationV3, ExecutionEncoder, @@ -16,9 +20,11 @@ pub use factory::{ PreparedAccountDeploymentV3, RawAccountDeploymentV1, RawAccountDeploymentV3, }; +/// Module containing types for using an account contract with only one signer. pub mod single_owner; pub use single_owner::{ExecutionEncoding, SingleOwnerAccount}; +/// Error when calling `prepared()` on a type when not all fields are populated. #[derive(Debug, thiserror::Error)] #[error("Not all fields are prepared")] pub struct NotPreparedError; diff --git a/starknet-accounts/src/single_owner.rs b/starknet-accounts/src/single_owner.rs index c615faf2..1c15bee8 100644 --- a/starknet-accounts/src/single_owner.rs +++ b/starknet-accounts/src/single_owner.rs @@ -8,6 +8,8 @@ use starknet_core::types::{contract::ComputeClassHashError, BlockId, BlockTag, F use starknet_providers::Provider; use starknet_signers::Signer; +/// A generic [`Account`] implementation for controlling account contracts that only have one signer +/// using ECDSA the STARK curve. #[derive(Debug, Clone)] pub struct SingleOwnerAccount where @@ -22,10 +24,13 @@ where encoding: ExecutionEncoding, } +/// Errors signing an execution/declaration request. #[derive(Debug, thiserror::Error)] pub enum SignError { + /// An error encountered by the signer implementation. #[error(transparent)] Signer(S), + /// Failure to compute the class hash of the class being declared. #[error(transparent)] ClassHash(ComputeClassHashError), } @@ -71,6 +76,7 @@ where } } + /// Sets a new block ID to run queries against. pub fn set_block_id(&mut self, block_id: BlockId) -> &Self { self.block_id = block_id; self From 7d8395f7da395c756985dd61d0dfc36b33713458 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 29 Jul 2024 16:54:32 +0800 Subject: [PATCH 28/54] docs: add docs for `starknet-contract` (#641) --- starknet-contract/src/factory.rs | 35 ++++++++++++++++++++++++++++++++ starknet-contract/src/lib.rs | 12 ++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/starknet-contract/src/factory.rs b/starknet-contract/src/factory.rs index 299ff0f1..57e25f61 100644 --- a/starknet-contract/src/factory.rs +++ b/starknet-contract/src/factory.rs @@ -20,6 +20,8 @@ const SELECTOR_DEPLOYCONTRACT: Felt = Felt::from_raw([ 18249998464715511309, ]); +/// A contract factory that acts as a blueprint for deploying Starknet smart contracts using the +/// Universal Deployer Contract. #[derive(Debug)] pub struct ContractFactory { class_hash: Felt, @@ -62,10 +64,15 @@ pub struct DeploymentV3<'f, A> { } impl ContractFactory { + /// Constructs a new [`ContractFactory`] from a class hash and an account. + /// + /// The [`ContractFactory`] created uses the default address for the Universal Deployer + /// Contract. To use a custom UDC deployment, use [`new_with_udc`](fn.new_with_udc) instead. pub const fn new(class_hash: Felt, account: A) -> Self { Self::new_with_udc(class_hash, account, UDC_ADDRESS) } + /// Constructs a new [`ContractFactory`] with a custom Universal Deployer Contract address. pub const fn new_with_udc(class_hash: Felt, account: A, udc_address: Felt) -> Self { Self { class_hash, @@ -79,6 +86,8 @@ impl ContractFactory where A: Account, { + /// Generates an instance of [`DeploymentV1`] for sending `INVOKE` v1 transactions for the + /// contract deployment. Pays transaction fees in `ETH`. pub const fn deploy_v1( &self, constructor_calldata: Vec, @@ -96,6 +105,8 @@ where } } + /// Generates an instance of [`DeploymentV3`] for sending `INVOKE` v3 transactions for the + /// contract deployment. Pays transaction fees in `STRK`. pub const fn deploy_v3( &self, constructor_calldata: Vec, @@ -115,6 +126,8 @@ where } } + /// Generates an instance of [`DeploymentV1`] for sending `INVOKE` v1 transactions for the + /// contract deployment. Pays transaction fees in `ETH`. #[deprecated = "use version specific variants (`deploy_v1` & `deploy_v3`) instead"] pub const fn deploy( &self, @@ -127,6 +140,7 @@ where } impl<'f, A> DeploymentV1<'f, A> { + /// Returns a new [`DeploymentV1`] with the `nonce`. pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), @@ -134,6 +148,7 @@ impl<'f, A> DeploymentV1<'f, A> { } } + /// Returns a new [`DeploymentV1`] with the `max_fee`. pub fn max_fee(self, max_fee: Felt) -> Self { Self { max_fee: Some(max_fee), @@ -141,6 +156,9 @@ impl<'f, A> DeploymentV1<'f, A> { } } + /// Returns a new [`DeploymentV1`] with the fee estimate multiplier. The multiplier is used + /// when transaction fee is not manually specified and must be fetched from a + /// [`Provider`](starknet_providers::Provider) instead. pub fn fee_estimate_multiplier(self, fee_estimate_multiplier: f64) -> Self { Self { fee_estimate_multiplier, @@ -150,6 +168,7 @@ impl<'f, A> DeploymentV1<'f, A> { } impl<'f, A> DeploymentV3<'f, A> { + /// Returns a new [`DeploymentV3`] with the `nonce`. pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), @@ -157,6 +176,7 @@ impl<'f, A> DeploymentV3<'f, A> { } } + /// Returns a new [`DeploymentV3`] with the `gas`. pub fn gas(self, gas: u64) -> Self { Self { gas: Some(gas), @@ -164,6 +184,7 @@ impl<'f, A> DeploymentV3<'f, A> { } } + /// Returns a new [`DeploymentV3`] with the `gas_price`. pub fn gas_price(self, gas_price: u128) -> Self { Self { gas_price: Some(gas_price), @@ -171,6 +192,9 @@ impl<'f, A> DeploymentV3<'f, A> { } } + /// Returns a new [`DeploymentV3`] with the gas amount estimate multiplier. The multiplier is + /// used when the gas amount is not manually specified and must be fetched from a + /// [`Provider`](starknet_providers::Provider) instead. pub fn gas_estimate_multiplier(self, gas_estimate_multiplier: f64) -> Self { Self { gas_estimate_multiplier, @@ -178,6 +202,9 @@ impl<'f, A> DeploymentV3<'f, A> { } } + /// Returns a new [`DeploymentV3`] with the gas price estimate multiplier. The multiplier is + /// used when the gas price is not manually specified and must be fetched from a + /// [`Provider`](starknet_providers::Provider) instead. pub fn gas_price_estimate_multiplier(self, gas_price_estimate_multiplier: f64) -> Self { Self { gas_price_estimate_multiplier, @@ -234,11 +261,14 @@ impl<'f, A> DeploymentV1<'f, A> where A: ConnectedAccount + Sync, { + /// Estimates transaction fees from a [`Provider`](starknet_providers::Provider). pub async fn estimate_fee(&self) -> Result> { let execution: ExecutionV1<'_, A> = self.into(); execution.estimate_fee().await } + /// Simulates the transaction from a [`Provider`](starknet_providers::Provider). Transaction + /// validation and fee transfer can be skipped. pub async fn simulate( &self, skip_validate: bool, @@ -248,6 +278,7 @@ where execution.simulate(skip_validate, skip_fee_charge).await } + /// Signs and broadcasts the transaction to the network. pub async fn send(&self) -> Result> { let execution: ExecutionV1<'_, A> = self.into(); execution.send().await @@ -258,11 +289,14 @@ impl<'f, A> DeploymentV3<'f, A> where A: ConnectedAccount + Sync, { + /// Estimates transaction fees from a [`Provider`](starknet_providers::Provider). pub async fn estimate_fee(&self) -> Result> { let execution: ExecutionV3<'_, A> = self.into(); execution.estimate_fee().await } + /// Simulates the transaction from a [`Provider`](starknet_providers::Provider). Transaction + /// validation and fee transfer can be skipped. pub async fn simulate( &self, skip_validate: bool, @@ -272,6 +306,7 @@ where execution.simulate(skip_validate, skip_fee_charge).await } + /// Signs and broadcasts the transaction to the network. pub async fn send(&self) -> Result> { let execution: ExecutionV3<'_, A> = self.into(); execution.send().await diff --git a/starknet-contract/src/lib.rs b/starknet-contract/src/lib.rs index cec06190..2a37967e 100644 --- a/starknet-contract/src/lib.rs +++ b/starknet-contract/src/lib.rs @@ -1,2 +1,12 @@ +//! Library for deploying and interacting with Starknet contracts. +//! +//! Currently, this crate only provides a single type [`ContractFactory`] for deploying contracts +//! using the Universal Deployer Contract. +//! +//! In the future, features like ABI-based contract binding generation will be added to allow type- +//! safe interaction with Starknet smart contracts. + +#![deny(missing_docs)] + mod factory; -pub use factory::ContractFactory; +pub use factory::{ContractFactory, DeploymentV1, DeploymentV3}; From d0d42d445d22dfa5c37180338b1f0d58c963408b Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 29 Jul 2024 17:02:47 +0800 Subject: [PATCH 29/54] docs: add docs for `starknet-macros` (#642) --- src/lib.rs | 2 ++ starknet-macros/src/lib.rs | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index cf90871b..ce1f491c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,8 @@ //! //! Contains procedural macros useful for this crate. +#![deny(missing_docs)] + #[doc = include_str!("../assets/CORE_README.md")] pub mod core { pub use starknet_core::*; diff --git a/starknet-macros/src/lib.rs b/starknet-macros/src/lib.rs index 79d1aade..eb7114ad 100644 --- a/starknet-macros/src/lib.rs +++ b/starknet-macros/src/lib.rs @@ -1,3 +1,8 @@ +//! Procedural macros for the `starknet` crate. This crate provides macros that help make defining +//! certain compile-time constants easier. + +#![deny(missing_docs)] + use proc_macro::TokenStream; use starknet_core::{ types::Felt, @@ -5,6 +10,7 @@ use starknet_core::{ }; use syn::{parse_macro_input, LitStr}; +/// Defines a compile-time constant for a entrypoint selector of a Starknet contract. #[proc_macro] pub fn selector(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as LitStr); @@ -26,6 +32,7 @@ pub fn selector(input: TokenStream) -> TokenStream { .unwrap() } +/// Defines a compile-time constant for a Cairo short string encoding from a human-readable string. #[proc_macro] pub fn short_string(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as LitStr); @@ -47,6 +54,8 @@ pub fn short_string(input: TokenStream) -> TokenStream { .unwrap() } +/// Defines a compile-time constant for a field element from its decimal or hexadecimal +/// representation. #[proc_macro] pub fn felt(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as LitStr); @@ -73,6 +82,7 @@ pub fn felt(input: TokenStream) -> TokenStream { .unwrap() } +/// Defines a compile-time constant for a field element from its decimal representation. #[proc_macro] pub fn felt_dec(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as LitStr); @@ -94,6 +104,7 @@ pub fn felt_dec(input: TokenStream) -> TokenStream { .unwrap() } +/// Defines a compile-time constant for a field element from its hexadecimal representation. #[proc_macro] pub fn felt_hex(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as LitStr); @@ -116,7 +127,7 @@ pub fn felt_hex(input: TokenStream) -> TokenStream { } #[cfg(feature = "use_imported_type")] -fn field_element_path() -> &'static str { +const fn field_element_path() -> &'static str { "Felt" } From 2774834e9a2dd86a4e93861f5b9686e8b706c766 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 29 Jul 2024 21:59:03 +0800 Subject: [PATCH 30/54] chore: use `coins-ledger` from crates.io (#643) A new version `0.12.0` has been released with the necessary patch. --- Cargo.lock | 5 +++-- starknet-signers/Cargo.toml | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1e87047..7841ce2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -346,8 +346,9 @@ dependencies = [ [[package]] name = "coins-ledger" -version = "0.11.1" -source = "git+https://github.com/xJonathanLEI/coins?rev=0e3be5db0b18b683433de6b666556b99c726e785#0e3be5db0b18b683433de6b666556b99c726e785" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab9bc0994d0aa0f4ade5f3a9baf4a8d936f250278c85a1124b401860454246ab" dependencies = [ "async-trait", "byteorder", diff --git a/starknet-signers/Cargo.toml b/starknet-signers/Cargo.toml index f608b25f..a51bb688 100644 --- a/starknet-signers/Cargo.toml +++ b/starknet-signers/Cargo.toml @@ -21,11 +21,9 @@ thiserror = "1.0.40" crypto-bigint = { version = "0.5.1", default-features = false } rand = { version = "0.8.5", features = ["std_rng"] } coins-bip32 = { version = "0.11.1", optional = true } +coins-ledger = { version = "0.12.0", default-features = false, optional = true } semver = { version = "1.0.23", optional = true } -# Using a fork until https://github.com/summa-tx/coins/issues/137 is fixed -coins-ledger = { git = "https://github.com/xJonathanLEI/coins", rev = "0e3be5db0b18b683433de6b666556b99c726e785", default-features = false, optional = true } - [target.'cfg(not(target_arch = "wasm32"))'.dependencies] eth-keystore = { version = "0.5.0", default-features = false } From f31e426a65225b9830bbf3c148f7ea05bf9dc257 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Tue, 30 Jul 2024 00:45:01 +0800 Subject: [PATCH 31/54] test: contract artifact deserliazation integrity (#644) Adds test cases that asserts contract artifacts are not corrupted whether deserialized directly or via the `ContractArtifact` enum. The test for `LegacyContractClass` - `test_legacy_artifact_deser_from_contract_artifact` - is ignored due to a known issue #392. --- starknet-core/src/types/contract/legacy.rs | 27 +++++++++++++++++++++ starknet-core/src/types/contract/mod.rs | 28 +++++++++++++++++----- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/starknet-core/src/types/contract/legacy.rs b/starknet-core/src/types/contract/legacy.rs index 4608bd7a..a6edda7f 100644 --- a/starknet-core/src/types/contract/legacy.rs +++ b/starknet-core/src/types/contract/legacy.rs @@ -984,6 +984,7 @@ fn should_skip_attributes_for_hinted_hash(value: &Option>) #[cfg(test)] mod tests { + use super::super::ContractArtifact; use super::*; #[derive(serde::Deserialize)] @@ -1007,6 +1008,32 @@ mod tests { } } + #[test] + #[ignore = "https://github.com/xJonathanLEI/starknet-rs/issues/392"] + fn test_legacy_artifact_deser_from_contract_artifact() { + for raw_artifact in [ + include_str!("../../../test-data/contracts/cairo0/artifacts/oz_account.txt"), + include_str!("../../../test-data/contracts/cairo0/artifacts/event_example.txt"), + include_str!("../../../test-data/contracts/cairo0/artifacts/pre-0.11.0/oz_account.txt"), + include_str!( + "../../../test-data/contracts/cairo0/artifacts/pre-0.11.0/event_example.txt" + ), + ] { + let direct_deser = serde_json::from_str::(raw_artifact).unwrap(); + let deser_via_contract_artifact = + match serde_json::from_str::(raw_artifact).unwrap() { + ContractArtifact::LegacyClass(class) => class, + _ => panic!("unexpected artifact type"), + }; + + // Class should be identical however it's deserialized + assert_eq!( + direct_deser.class_hash().unwrap(), + deser_via_contract_artifact.class_hash().unwrap() + ); + } + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_contract_class_hash() { diff --git a/starknet-core/src/types/contract/mod.rs b/starknet-core/src/types/contract/mod.rs index 8d50753f..1d626b42 100644 --- a/starknet-core/src/types/contract/mod.rs +++ b/starknet-core/src/types/contract/mod.rs @@ -1023,10 +1023,18 @@ mod tests { include_str!("../../../test-data/contracts/cairo2/artifacts/erc20_sierra.txt"), include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_sierra.txt"), ] { - match serde_json::from_str::(raw_artifact) { - Ok(ContractArtifact::SierraClass(_)) => {} + let direct_deser = serde_json::from_str::(raw_artifact).unwrap(); + let via_contract_artifact = match serde_json::from_str::(raw_artifact) + { + Ok(ContractArtifact::SierraClass(class)) => class, _ => panic!("Unexpected result"), - } + }; + + // Class should be identical however it's deserialized + assert_eq!( + direct_deser.class_hash().unwrap(), + via_contract_artifact.class_hash().unwrap() + ); } } @@ -1040,10 +1048,18 @@ mod tests { include_str!("../../../test-data/contracts/cairo2/artifacts/erc20_compiled.txt"), include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_compiled.txt"), ] { - match serde_json::from_str::(raw_artifact) { - Ok(ContractArtifact::CompiledClass(_)) => {} + let direct_deser = serde_json::from_str::(raw_artifact).unwrap(); + let via_contract_artifact = match serde_json::from_str::(raw_artifact) + { + Ok(ContractArtifact::CompiledClass(class)) => class, _ => panic!("Unexpected result"), - } + }; + + // Class should be identical however it's deserialized + assert_eq!( + direct_deser.class_hash().unwrap(), + via_contract_artifact.class_hash().unwrap() + ); } } From 2ddc69479d326ed154df438d22f2d720fbba746e Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Fri, 9 Aug 2024 09:12:46 -0600 Subject: [PATCH 32/54] feat: dynamic signer interactivity (#648) --- examples/mint_tokens.rs | 4 +-- examples/transfer_with_ledger.rs | 4 +-- starknet-accounts/src/account/declaration.rs | 28 +++++++++++++++---- starknet-accounts/src/account/execution.rs | 27 ++++++++++++------ starknet-accounts/src/account/mod.rs | 19 ++++++------- starknet-accounts/src/factory/argent.rs | 5 ++-- .../src/factory/open_zeppelin.rs | 5 ++-- starknet-accounts/src/lib.rs | 3 -- starknet-accounts/src/single_owner.rs | 10 +++---- .../tests/single_owner_account.rs | 4 +-- starknet-contract/src/factory.rs | 4 +-- .../src => starknet-core/src/types}/call.rs | 4 ++- starknet-core/src/types/mod.rs | 3 ++ starknet-signers/src/ledger.rs | 4 +-- starknet-signers/src/lib.rs | 2 +- starknet-signers/src/local_wallet.rs | 4 +-- starknet-signers/src/signer.rs | 24 ++++++++++++++-- 17 files changed, 102 insertions(+), 52 deletions(-) rename {starknet-accounts/src => starknet-core/src/types}/call.rs (88%) diff --git a/examples/mint_tokens.rs b/examples/mint_tokens.rs index 64fc7ada..7a2deaec 100644 --- a/examples/mint_tokens.rs +++ b/examples/mint_tokens.rs @@ -1,8 +1,8 @@ use starknet::{ - accounts::{Account, Call, ExecutionEncoding, SingleOwnerAccount}, + accounts::{Account, ExecutionEncoding, SingleOwnerAccount}, core::{ chain_id, - types::{BlockId, BlockTag, Felt}, + types::{BlockId, BlockTag, Call, Felt}, utils::get_selector_from_name, }, providers::{ diff --git a/examples/transfer_with_ledger.rs b/examples/transfer_with_ledger.rs index 223da492..d6fd1fff 100644 --- a/examples/transfer_with_ledger.rs +++ b/examples/transfer_with_ledger.rs @@ -1,8 +1,8 @@ use starknet::{ - accounts::{Account, Call, ExecutionEncoding, SingleOwnerAccount}, + accounts::{Account, ExecutionEncoding, SingleOwnerAccount}, core::{ chain_id, - types::{BlockId, BlockTag, Felt}, + types::{BlockId, BlockTag, Call, Felt}, utils::get_selector_from_name, }, macros::felt, diff --git a/starknet-accounts/src/account/declaration.rs b/starknet-accounts/src/account/declaration.rs index 8efe9b59..cca83010 100644 --- a/starknet-accounts/src/account/declaration.rs +++ b/starknet-accounts/src/account/declaration.rs @@ -17,6 +17,7 @@ use starknet_core::{ }; use starknet_crypto::PoseidonHasher; use starknet_providers::Provider; +use starknet_signers::SignerInteractivityContext; use std::sync::Arc; /// Cairo string for "declare" @@ -209,7 +210,9 @@ where &self, nonce: Felt, ) -> Result> { - let skip_signature = self.account.is_signer_interactive(); + let skip_signature = self + .account + .is_signer_interactive(SignerInteractivityContext::Other); let prepared = PreparedDeclarationV2 { account: self.account, @@ -245,7 +248,10 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { - let skip_signature = if self.account.is_signer_interactive() { + let skip_signature = if self + .account + .is_signer_interactive(SignerInteractivityContext::Other) + { // If signer is interactive, we would try to minimize signing requests. However, if the // caller has decided to not skip validation, it's best we still request a real // signature, as otherwise the simulation would most likely fail. @@ -519,7 +525,9 @@ where &self, nonce: Felt, ) -> Result> { - let skip_signature = self.account.is_signer_interactive(); + let skip_signature = self + .account + .is_signer_interactive(SignerInteractivityContext::Other); let prepared = PreparedDeclarationV3 { account: self.account, @@ -556,7 +564,10 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { - let skip_signature = if self.account.is_signer_interactive() { + let skip_signature = if self + .account + .is_signer_interactive(SignerInteractivityContext::Other) + { // If signer is interactive, we would try to minimize signing requests. However, if the // caller has decided to not skip validation, it's best we still request a real // signature, as otherwise the simulation would most likely fail. @@ -753,7 +764,9 @@ where &self, nonce: Felt, ) -> Result> { - let skip_signature = self.account.is_signer_interactive(); + let skip_signature = self + .account + .is_signer_interactive(SignerInteractivityContext::Other); let prepared = PreparedLegacyDeclaration { account: self.account, @@ -788,7 +801,10 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { - let skip_signature = if self.account.is_signer_interactive() { + let skip_signature = if self + .account + .is_signer_interactive(SignerInteractivityContext::Other) + { // If signer is interactive, we would try to minimize signing requests. However, if the // caller has decided to not skip validation, it's best we still request a real // signature, as otherwise the simulation would most likely fail. diff --git a/starknet-accounts/src/account/execution.rs b/starknet-accounts/src/account/execution.rs index b96ee505..c3f75f38 100644 --- a/starknet-accounts/src/account/execution.rs +++ b/starknet-accounts/src/account/execution.rs @@ -2,19 +2,20 @@ use super::{ super::NotPreparedError, Account, AccountError, ConnectedAccount, ExecutionV1, ExecutionV3, PreparedExecutionV1, PreparedExecutionV3, RawExecutionV1, RawExecutionV3, }; -use crate::{Call, ExecutionEncoder}; +use crate::ExecutionEncoder; use starknet_core::{ crypto::compute_hash_on_elements, types::{ BroadcastedInvokeTransaction, BroadcastedInvokeTransactionV1, - BroadcastedInvokeTransactionV3, BroadcastedTransaction, DataAvailabilityMode, FeeEstimate, - Felt, InvokeTransactionResult, ResourceBounds, ResourceBoundsMapping, SimulatedTransaction, - SimulationFlag, SimulationFlagForEstimateFee, + BroadcastedInvokeTransactionV3, BroadcastedTransaction, Call, DataAvailabilityMode, + FeeEstimate, Felt, InvokeTransactionResult, ResourceBounds, ResourceBoundsMapping, + SimulatedTransaction, SimulationFlag, SimulationFlagForEstimateFee, }, }; use starknet_crypto::PoseidonHasher; use starknet_providers::Provider; +use starknet_signers::SignerInteractivityContext; /// Cairo string for "invoke" const PREFIX_INVOKE: Felt = Felt::from_raw([ @@ -271,7 +272,9 @@ where &self, nonce: Felt, ) -> Result> { - let skip_signature = self.account.is_signer_interactive(); + let skip_signature = self + .account + .is_signer_interactive(SignerInteractivityContext::Execution { calls: &self.calls }); let prepared = PreparedExecutionV1 { account: self.account, @@ -309,7 +312,10 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { - let skip_signature = if self.account.is_signer_interactive() { + let skip_signature = if self + .account + .is_signer_interactive(SignerInteractivityContext::Execution { calls: &self.calls }) + { // If signer is interactive, we would try to minimize signing requests. However, if the // caller has decided to not skip validation, it's best we still request a real // signature, as otherwise the simulation would most likely fail. @@ -498,7 +504,9 @@ where &self, nonce: Felt, ) -> Result> { - let skip_signature = self.account.is_signer_interactive(); + let skip_signature = self + .account + .is_signer_interactive(SignerInteractivityContext::Execution { calls: &self.calls }); let prepared = PreparedExecutionV3 { account: self.account, @@ -537,7 +545,10 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { - let skip_signature = if self.account.is_signer_interactive() { + let skip_signature = if self + .account + .is_signer_interactive(SignerInteractivityContext::Execution { calls: &self.calls }) + { // If signer is interactive, we would try to minimize signing requests. However, if the // caller has decided to not skip validation, it's best we still request a real // signature, as otherwise the simulation would most likely fail. diff --git a/starknet-accounts/src/account/mod.rs b/starknet-accounts/src/account/mod.rs index a3e19f54..4979377d 100644 --- a/starknet-accounts/src/account/mod.rs +++ b/starknet-accounts/src/account/mod.rs @@ -1,12 +1,11 @@ -use crate::Call; - use async_trait::async_trait; use auto_impl::auto_impl; use starknet_core::types::{ contract::{legacy::LegacyContractClass, CompressProgramError, ComputeClassHashError}, - BlockId, BlockTag, Felt, FlattenedSierraClass, + BlockId, BlockTag, Call, Felt, FlattenedSierraClass, }; use starknet_providers::{Provider, ProviderError}; +use starknet_signers::SignerInteractivityContext; use std::{error::Error, sync::Arc}; mod declaration; @@ -89,7 +88,7 @@ pub trait Account: ExecutionEncoder + Sized { /// /// This affects how an account makes decision on whether to request a real signature for /// estimation/simulation purposes. - fn is_signer_interactive(&self) -> bool; + fn is_signer_interactive(&self, context: SignerInteractivityContext<'_>) -> bool; /// Generates an instance of [`ExecutionV1`] for sending `INVOKE` v1 transactions. Pays /// transaction fees in `ETH`. @@ -465,8 +464,8 @@ where .await } - fn is_signer_interactive(&self) -> bool { - (*self).is_signer_interactive() + fn is_signer_interactive(&self, context: SignerInteractivityContext<'_>) -> bool { + (*self).is_signer_interactive(context) } } @@ -532,8 +531,8 @@ where .await } - fn is_signer_interactive(&self) -> bool { - self.as_ref().is_signer_interactive() + fn is_signer_interactive(&self, context: SignerInteractivityContext<'_>) -> bool { + self.as_ref().is_signer_interactive(context) } } @@ -599,8 +598,8 @@ where .await } - fn is_signer_interactive(&self) -> bool { - self.as_ref().is_signer_interactive() + fn is_signer_interactive(&self, context: SignerInteractivityContext<'_>) -> bool { + self.as_ref().is_signer_interactive(context) } } diff --git a/starknet-accounts/src/factory/argent.rs b/starknet-accounts/src/factory/argent.rs index 23bf3d7f..0a3b3a6c 100644 --- a/starknet-accounts/src/factory/argent.rs +++ b/starknet-accounts/src/factory/argent.rs @@ -6,7 +6,7 @@ use crate::{ use async_trait::async_trait; use starknet_core::types::{BlockId, BlockTag, Felt}; use starknet_providers::Provider; -use starknet_signers::Signer; +use starknet_signers::{Signer, SignerInteractivityContext}; /// [`AccountFactory`] implementation for deploying `Argent X` account contracts. #[derive(Debug)] @@ -78,7 +78,8 @@ where } fn is_signer_interactive(&self) -> bool { - self.signer.is_interactive() + self.signer + .is_interactive(SignerInteractivityContext::Other) } fn block_id(&self) -> BlockId { diff --git a/starknet-accounts/src/factory/open_zeppelin.rs b/starknet-accounts/src/factory/open_zeppelin.rs index 90c32722..6c20a9f4 100644 --- a/starknet-accounts/src/factory/open_zeppelin.rs +++ b/starknet-accounts/src/factory/open_zeppelin.rs @@ -6,7 +6,7 @@ use crate::{ use async_trait::async_trait; use starknet_core::types::{BlockId, BlockTag, Felt}; use starknet_providers::Provider; -use starknet_signers::Signer; +use starknet_signers::{Signer, SignerInteractivityContext}; /// [`AccountFactory`] implementation for deploying `OpenZeppelin` account contracts. #[derive(Debug)] @@ -75,7 +75,8 @@ where } fn is_signer_interactive(&self) -> bool { - self.signer.is_interactive() + self.signer + .is_interactive(SignerInteractivityContext::Other) } fn block_id(&self) -> BlockId { diff --git a/starknet-accounts/src/lib.rs b/starknet-accounts/src/lib.rs index 5da9d090..869e5c90 100644 --- a/starknet-accounts/src/lib.rs +++ b/starknet-accounts/src/lib.rs @@ -10,9 +10,6 @@ pub use account::{ RawDeclarationV3, RawExecutionV1, RawExecutionV3, RawLegacyDeclaration, }; -mod call; -pub use call::Call; - mod factory; pub use factory::{ argent::ArgentAccountFactory, open_zeppelin::OpenZeppelinAccountFactory, AccountDeploymentV1, diff --git a/starknet-accounts/src/single_owner.rs b/starknet-accounts/src/single_owner.rs index 1c15bee8..d954bd70 100644 --- a/starknet-accounts/src/single_owner.rs +++ b/starknet-accounts/src/single_owner.rs @@ -1,12 +1,12 @@ use crate::{ - Account, Call, ConnectedAccount, ExecutionEncoder, RawDeclarationV2, RawDeclarationV3, + Account, ConnectedAccount, ExecutionEncoder, RawDeclarationV2, RawDeclarationV3, RawExecutionV1, RawExecutionV3, RawLegacyDeclaration, }; use async_trait::async_trait; -use starknet_core::types::{contract::ComputeClassHashError, BlockId, BlockTag, Felt}; +use starknet_core::types::{contract::ComputeClassHashError, BlockId, BlockTag, Call, Felt}; use starknet_providers::Provider; -use starknet_signers::Signer; +use starknet_signers::{Signer, SignerInteractivityContext}; /// A generic [`Account`] implementation for controlling account contracts that only have one signer /// using ECDSA the STARK curve. @@ -177,8 +177,8 @@ where Ok(vec![signature.r, signature.s]) } - fn is_signer_interactive(&self) -> bool { - self.signer.is_interactive() + fn is_signer_interactive(&self, context: SignerInteractivityContext<'_>) -> bool { + self.signer.is_interactive(context) } } diff --git a/starknet-accounts/tests/single_owner_account.rs b/starknet-accounts/tests/single_owner_account.rs index bc1febe8..1598bdc9 100644 --- a/starknet-accounts/tests/single_owner_account.rs +++ b/starknet-accounts/tests/single_owner_account.rs @@ -1,5 +1,5 @@ use starknet_accounts::{ - Account, AccountError, Call, ConnectedAccount, ExecutionEncoding, SingleOwnerAccount, + Account, AccountError, ConnectedAccount, ExecutionEncoding, SingleOwnerAccount, }; use starknet_core::{ types::{ @@ -7,7 +7,7 @@ use starknet_core::{ legacy::{LegacyContractClass, RawLegacyAbiEntry, RawLegacyFunction}, SierraClass, }, - BlockId, BlockTag, Felt, StarknetError, + BlockId, BlockTag, Call, Felt, StarknetError, }, utils::get_selector_from_name, }; diff --git a/starknet-contract/src/factory.rs b/starknet-contract/src/factory.rs index 57e25f61..65416722 100644 --- a/starknet-contract/src/factory.rs +++ b/starknet-contract/src/factory.rs @@ -1,6 +1,6 @@ -use starknet_accounts::{Account, AccountError, Call, ConnectedAccount, ExecutionV1, ExecutionV3}; +use starknet_accounts::{Account, AccountError, ConnectedAccount, ExecutionV1, ExecutionV3}; use starknet_core::{ - types::{FeeEstimate, Felt, InvokeTransactionResult, SimulatedTransaction}, + types::{Call, FeeEstimate, Felt, InvokeTransactionResult, SimulatedTransaction}, utils::{get_udc_deployed_address, UdcUniqueSettings, UdcUniqueness}, }; diff --git a/starknet-accounts/src/call.rs b/starknet-core/src/types/call.rs similarity index 88% rename from starknet-accounts/src/call.rs rename to starknet-core/src/types/call.rs index 0788e011..bf9ac864 100644 --- a/starknet-accounts/src/call.rs +++ b/starknet-core/src/types/call.rs @@ -1,4 +1,6 @@ -use starknet_core::types::Felt; +use alloc::vec::*; + +use crate::types::Felt; /// A contract call as part of a multi-call execution request. #[derive(Debug, Clone)] diff --git a/starknet-core/src/types/mod.rs b/starknet-core/src/types/mod.rs index 3e7756b4..5f8e6db3 100644 --- a/starknet-core/src/types/mod.rs +++ b/starknet-core/src/types/mod.rs @@ -62,6 +62,9 @@ pub use receipt_block::ReceiptBlock; mod msg; pub use msg::MsgToL2; +mod call; +pub use call::Call; + // TODO: move generated request code to `starknet-providers` /// Module containing JSON-RPC request types. pub mod requests; diff --git a/starknet-signers/src/ledger.rs b/starknet-signers/src/ledger.rs index fd139b06..2d385242 100644 --- a/starknet-signers/src/ledger.rs +++ b/starknet-signers/src/ledger.rs @@ -8,7 +8,7 @@ use crypto_bigint::{ArrayEncoding, U256}; use semver::Version; use starknet_core::{crypto::Signature, types::Felt}; -use crate::{Signer, VerifyingKey}; +use crate::{Signer, SignerInteractivityContext, VerifyingKey}; pub use coins_bip32::path::DerivationPath; @@ -128,7 +128,7 @@ impl Signer for LedgerSigner { self.app.sign_hash(self.derivation_path.clone(), hash).await } - fn is_interactive(&self) -> bool { + fn is_interactive(&self, _context: SignerInteractivityContext<'_>) -> bool { true } } diff --git a/starknet-signers/src/lib.rs b/starknet-signers/src/lib.rs index 59f9d292..14ffc9a7 100644 --- a/starknet-signers/src/lib.rs +++ b/starknet-signers/src/lib.rs @@ -9,7 +9,7 @@ pub use key_pair::{SigningKey, VerifyingKey}; pub use key_pair::KeystoreError; mod signer; -pub use signer::Signer; +pub use signer::{Signer, SignerInteractivityContext}; /// Module containing types related to the use of a simple in-memory signer. pub mod local_wallet; diff --git a/starknet-signers/src/local_wallet.rs b/starknet-signers/src/local_wallet.rs index 0ad14c61..4f220fbe 100644 --- a/starknet-signers/src/local_wallet.rs +++ b/starknet-signers/src/local_wallet.rs @@ -1,4 +1,4 @@ -use crate::{Infallible, Signer, SigningKey, VerifyingKey}; +use crate::{Infallible, Signer, SignerInteractivityContext, SigningKey, VerifyingKey}; use async_trait::async_trait; use starknet_core::{ @@ -42,7 +42,7 @@ impl Signer for LocalWallet { Ok(self.private_key.sign(hash)?) } - fn is_interactive(&self) -> bool { + fn is_interactive(&self, _context: SignerInteractivityContext<'_>) -> bool { false } } diff --git a/starknet-signers/src/signer.rs b/starknet-signers/src/signer.rs index 2a7d3a46..f7569b10 100644 --- a/starknet-signers/src/signer.rs +++ b/starknet-signers/src/signer.rs @@ -2,7 +2,10 @@ use crate::VerifyingKey; use async_trait::async_trait; use auto_impl::auto_impl; -use starknet_core::{crypto::Signature, types::Felt}; +use starknet_core::{ + crypto::Signature, + types::{Call, Felt}, +}; use std::error::Error; /// Any signer that can provide a public key as [`Felt`], and sign a raw hash for a signature @@ -38,5 +41,22 @@ pub trait Signer { /// non-interactive signers, it's fine to sign multiple times for getting the most accurate /// estimation/simulation possible; but with interactive signers, they would accept less /// accurate results to minimize signing requests. - fn is_interactive(&self) -> bool; + fn is_interactive(&self, context: SignerInteractivityContext<'_>) -> bool; +} + +/// Context for helping signer implementations make decisions on whether to act interactively or +/// not, useful for signers with dynamic interactivity. +/// +/// This type only exposes execution details as context, with everything else falling under the +/// `Other` variant, as it's deemed very much pointless to act differently in those scenarios. +/// When an execution is requested, only the list of calls is exposed. +#[derive(Debug, Clone, Copy)] +pub enum SignerInteractivityContext<'a> { + /// An execution is being requested. + Execution { + /// The list of calls being authorized. + calls: &'a [Call], + }, + /// A class declaration or account deployment is being requested. + Other, } From 95fb1b6e27150529b6246386ab77d7897a1f8966 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 26 Aug 2024 18:51:28 +0800 Subject: [PATCH 33/54] chore: make clippy happy again (#652) --- .github/workflows/lint.yaml | 2 +- starknet-accounts/tests/single_owner_account.rs | 8 ++++---- starknet-contract/tests/contract_deployment.rs | 4 ++-- starknet-core/src/types/eth_address.rs | 16 ++++++++-------- starknet-core/src/types/mod.rs | 1 + 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 1a8df083..43bb0dab 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -81,7 +81,7 @@ jobs: - name: "Set allowed lints" run: | if [ "${{ matrix.toolchain }}" == "nightly" ]; then - echo "ALLOWED=-A non_local_definitions" >> $GITHUB_ENV + echo "ALLOWED=-A non_local_definitions -A clippy::too_long_first_doc_paragraph" >> $GITHUB_ENV else echo "ALLOWED=" >> $GITHUB_ENV fi diff --git a/starknet-accounts/tests/single_owner_account.rs b/starknet-accounts/tests/single_owner_account.rs index 1598bdc9..808093f4 100644 --- a/starknet-accounts/tests/single_owner_account.rs +++ b/starknet-accounts/tests/single_owner_account.rs @@ -354,8 +354,8 @@ async fn can_execute_eth_transfer_invoke_v3_inner( selector: get_selector_from_name("transfer").unwrap(), calldata: vec![Felt::from_hex("0x1234").unwrap(), Felt::ONE, Felt::ZERO], }]) - .gas(200000) - .gas_price(500000000000000) + .gas(100000) + .gas_price(800000000000000) .send() .await .unwrap(); @@ -544,8 +544,8 @@ async fn can_declare_cairo1_contract_v3_inner( Arc::new(flattened_class), Felt::from_hex(&hashes.compiled_class_hash).unwrap(), ) - .gas(200000) - .gas_price(500000000000000) + .gas(100000) + .gas_price(800000000000000) .send() .await .unwrap(); diff --git a/starknet-contract/tests/contract_deployment.rs b/starknet-contract/tests/contract_deployment.rs index eff7f2cc..5720d100 100644 --- a/starknet-contract/tests/contract_deployment.rs +++ b/starknet-contract/tests/contract_deployment.rs @@ -80,8 +80,8 @@ async fn can_deploy_contract_to_alpha_sepolia_with_invoke_v3() { let result = factory .deploy_v3(vec![Felt::ONE], Felt::from_bytes_be(&salt_buffer), true) - .gas(200000) - .gas_price(500000000000000) + .gas(100000) + .gas_price(800000000000000) .send() .await; diff --git a/starknet-core/src/types/eth_address.rs b/starknet-core/src/types/eth_address.rs index ab81606f..bfe2924d 100644 --- a/starknet-core/src/types/eth_address.rs +++ b/starknet-core/src/types/eth_address.rs @@ -207,7 +207,7 @@ impl From<[u8; 20]> for EthAddress { #[cfg(test)] mod tests { - use super::{EthAddress, Felt, FromBytesSliceError, FromFieldElementError}; + use super::{EthAddress, Felt}; use alloc::vec::*; @@ -291,11 +291,12 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_eth_address_from_felt_error() { - match EthAddress::from_felt( + if EthAddress::from_felt( &Felt::from_hex("0x10000000000000000000000000000000000000000").unwrap(), - ) { - Ok(_) => panic!("Expected error, but got Ok"), - Err(FromFieldElementError) => {} + ) + .is_ok() + { + panic!("Expected error, but got Ok"); } } @@ -304,9 +305,8 @@ mod tests { fn test_eth_address_from_slice_invalid_slice() { let buffer: Vec = vec![0, 1, 2, 3, 4, 5, 6, 7]; - match EthAddress::try_from(&buffer[0..4]) { - Ok(_) => panic!("Expected error, but got Ok"), - Err(FromBytesSliceError) => {} + if EthAddress::try_from(&buffer[0..4]).is_ok() { + panic!("Expected error, but got Ok"); } } } diff --git a/starknet-core/src/types/mod.rs b/starknet-core/src/types/mod.rs index 5f8e6db3..174968f5 100644 --- a/starknet-core/src/types/mod.rs +++ b/starknet-core/src/types/mod.rs @@ -426,6 +426,7 @@ pub enum TransactionTrace { } /// The execution result of a function invocation. +#[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(untagged)] pub enum ExecuteInvocation { From 660a7323169bbcdaea71b4f0e939631e3aaabd45 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 26 Aug 2024 23:11:35 +0800 Subject: [PATCH 34/54] fix: wrong type for `bytecode_segment_lengths` (#651) --- starknet-core/src/types/contract/mod.rs | 85 +++++++++++-------- .../cairo2.6/artifacts/trivial.hashes.json | 4 + .../cairo2.6/artifacts/trivial_compiled.txt | 12 +++ .../cairo2.6/artifacts/trivial_sierra.txt | 34 ++++++++ .../cairo2.6/contracts/trivial.cairo | 10 +++ .../cairo2.6/docker_entry_compile.sh | 1 + .../contracts/cairo2.6/docker_entry_hashes.sh | 1 + 7 files changed, 110 insertions(+), 37 deletions(-) create mode 100644 starknet-core/test-data/contracts/cairo2.6/artifacts/trivial.hashes.json create mode 100644 starknet-core/test-data/contracts/cairo2.6/artifacts/trivial_compiled.txt create mode 100644 starknet-core/test-data/contracts/cairo2.6/artifacts/trivial_sierra.txt create mode 100644 starknet-core/test-data/contracts/cairo2.6/contracts/trivial.cairo diff --git a/starknet-core/src/types/contract/mod.rs b/starknet-core/src/types/contract/mod.rs index 1d626b42..d7ee6d62 100644 --- a/starknet-core/src/types/contract/mod.rs +++ b/starknet-core/src/types/contract/mod.rs @@ -83,8 +83,8 @@ pub struct CompiledClass { /// Represents the structure of the bytecode segments, using a nested list of segment lengths. /// For example, [2, [3, 4]] represents a bytecode with 2 segments, the first is a leaf of /// length 2 and the second is a node with 2 children of lengths 3 and 4. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub bytecode_segment_lengths: Vec, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub bytecode_segment_lengths: Option, /// Hints for non-determinism. pub hints: Vec, /// Same as `hints` but represented in Python code, which can be generated by the compiler but @@ -658,42 +658,45 @@ impl CompiledClass { ); // Hashes bytecode - hasher.update(if self.bytecode_segment_lengths.is_empty() { - // Pre-Sierra-1.5.0 compiled classes - poseidon_hash_many(&self.bytecode) - } else { - // `bytecode_segment_lengths` was added since Sierra 1.5.0 and changed hash calculation. - // This implementation here is basically a direct translation of the Python code from - // `cairo-lang` v0.13.1. The goal was simply to have a working implementation as quickly - // as possible. There should be some optimizations to be made here. - // TODO: review how this can be optimized - - // NOTE: this looks extremely inefficient. Maybe just use a number for tracking instead? - let mut rev_visited_pcs: Vec = (0..(self.bytecode.len() as u64)).rev().collect(); - - let (res, total_len) = Self::create_bytecode_segment_structure_inner( - &self.bytecode, - &IntOrList::List(self.bytecode_segment_lengths.clone()), - &mut rev_visited_pcs, - &mut 0, - )?; - - if total_len != self.bytecode.len() as u64 { - return Err(ComputeClassHashError::BytecodeSegmentLengthMismatch( - BytecodeSegmentLengthMismatchError { - segment_length: total_len as usize, - bytecode_length: self.bytecode.len(), - }, - )); - } - if !rev_visited_pcs.is_empty() { - return Err(ComputeClassHashError::PcOutOfRange(PcOutOfRangeError { - pc: rev_visited_pcs[rev_visited_pcs.len() - 1], - })); - } + hasher.update( + if let Some(bytecode_segment_lengths) = self.bytecode_segment_lengths.clone() { + // `bytecode_segment_lengths` was added since Sierra 1.5.0 and changed hash calculation. + // This implementation here is basically a direct translation of the Python code from + // `cairo-lang` v0.13.1. The goal was simply to have a working implementation as quickly + // as possible. There should be some optimizations to be made here. + // TODO: review how this can be optimized + + // NOTE: this looks extremely inefficient. Maybe just use a number for tracking instead? + let mut rev_visited_pcs: Vec = + (0..(self.bytecode.len() as u64)).rev().collect(); + + let (res, total_len) = Self::create_bytecode_segment_structure_inner( + &self.bytecode, + &bytecode_segment_lengths, + &mut rev_visited_pcs, + &mut 0, + )?; + + if total_len != self.bytecode.len() as u64 { + return Err(ComputeClassHashError::BytecodeSegmentLengthMismatch( + BytecodeSegmentLengthMismatchError { + segment_length: total_len as usize, + bytecode_length: self.bytecode.len(), + }, + )); + } + if !rev_visited_pcs.is_empty() { + return Err(ComputeClassHashError::PcOutOfRange(PcOutOfRangeError { + pc: rev_visited_pcs[rev_visited_pcs.len() - 1], + })); + } - res.hash() - }); + res.hash() + } else { + // Pre-Sierra-1.5.0 compiled classes + poseidon_hash_many(&self.bytecode) + }, + ); Ok(hasher.finalize()) } @@ -1022,6 +1025,7 @@ mod tests { include_str!("../../../test-data/contracts/cairo2/artifacts/abi_types_sierra.txt"), include_str!("../../../test-data/contracts/cairo2/artifacts/erc20_sierra.txt"), include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_sierra.txt"), + include_str!("../../../test-data/contracts/cairo2.6/artifacts/trivial_sierra.txt"), ] { let direct_deser = serde_json::from_str::(raw_artifact).unwrap(); let via_contract_artifact = match serde_json::from_str::(raw_artifact) @@ -1047,6 +1051,7 @@ mod tests { include_str!("../../../test-data/contracts/cairo2/artifacts/abi_types_compiled.txt"), include_str!("../../../test-data/contracts/cairo2/artifacts/erc20_compiled.txt"), include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_compiled.txt"), + include_str!("../../../test-data/contracts/cairo2.6/artifacts/trivial_compiled.txt"), ] { let direct_deser = serde_json::from_str::(raw_artifact).unwrap(); let via_contract_artifact = match serde_json::from_str::(raw_artifact) @@ -1133,6 +1138,12 @@ mod tests { include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_compiled.txt"), include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20.hashes.json"), ), + ( + include_str!( + "../../../test-data/contracts/cairo2.6/artifacts/trivial_compiled.txt" + ), + include_str!("../../../test-data/contracts/cairo2.6/artifacts/trivial.hashes.json"), + ), ] { let compiled_class = serde_json::from_str::(raw_artifact).unwrap(); let computed_hash = compiled_class.class_hash().unwrap(); diff --git a/starknet-core/test-data/contracts/cairo2.6/artifacts/trivial.hashes.json b/starknet-core/test-data/contracts/cairo2.6/artifacts/trivial.hashes.json new file mode 100644 index 00000000..8fe9ca8c --- /dev/null +++ b/starknet-core/test-data/contracts/cairo2.6/artifacts/trivial.hashes.json @@ -0,0 +1,4 @@ +{ + "sierra_class_hash": "0x7585639b4e793743860f2761d81e070157ae8d0fc8e518a8cd9069eb2a40010", + "compiled_class_hash": "0x317d3ac2cf840e487b6d0014a75f0cf507dff0bc143c710388e323487089bfa" +} diff --git a/starknet-core/test-data/contracts/cairo2.6/artifacts/trivial_compiled.txt b/starknet-core/test-data/contracts/cairo2.6/artifacts/trivial_compiled.txt new file mode 100644 index 00000000..09fb9b21 --- /dev/null +++ b/starknet-core/test-data/contracts/cairo2.6/artifacts/trivial_compiled.txt @@ -0,0 +1,12 @@ +{ + "prime": "0x800000000000011000000000000000000000000000000000000000000000001", + "compiler_version": "2.6.2", + "bytecode": [], + "bytecode_segment_lengths": 0, + "hints": [], + "entry_points_by_type": { + "EXTERNAL": [], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + } +} \ No newline at end of file diff --git a/starknet-core/test-data/contracts/cairo2.6/artifacts/trivial_sierra.txt b/starknet-core/test-data/contracts/cairo2.6/artifacts/trivial_sierra.txt new file mode 100644 index 00000000..068b9022 --- /dev/null +++ b/starknet-core/test-data/contracts/cairo2.6/artifacts/trivial_sierra.txt @@ -0,0 +1,34 @@ +{ + "sierra_program": [ + "0x1", + "0x5", + "0x0", + "0x2", + "0x6", + "0x2", + "0x1", + "0xff", + "0x0", + "0x4", + "0x0" + ], + "sierra_program_debug_info": { + "type_names": [], + "libfunc_names": [], + "user_func_names": [] + }, + "contract_class_version": "0.1.0", + "entry_points_by_type": { + "EXTERNAL": [], + "L1_HANDLER": [], + "CONSTRUCTOR": [] + }, + "abi": [ + { + "type": "event", + "name": "trivial::trivial::Trivial::Event", + "kind": "enum", + "variants": [] + } + ] +} \ No newline at end of file diff --git a/starknet-core/test-data/contracts/cairo2.6/contracts/trivial.cairo b/starknet-core/test-data/contracts/cairo2.6/contracts/trivial.cairo new file mode 100644 index 00000000..1e978c3d --- /dev/null +++ b/starknet-core/test-data/contracts/cairo2.6/contracts/trivial.cairo @@ -0,0 +1,10 @@ +#[starknet::contract] +mod Trivial { + #[storage] + struct Storage {} + + #[abi(embed_v0)] + fn something(ref self: ContractState) -> felt252 { + 1 + } +} diff --git a/starknet-core/test-data/contracts/cairo2.6/docker_entry_compile.sh b/starknet-core/test-data/contracts/cairo2.6/docker_entry_compile.sh index da07484a..51ba4d14 100755 --- a/starknet-core/test-data/contracts/cairo2.6/docker_entry_compile.sh +++ b/starknet-core/test-data/contracts/cairo2.6/docker_entry_compile.sh @@ -11,3 +11,4 @@ compile () { } compile "/contracts/erc20.cairo" "/artifacts/erc20" +compile "/contracts/trivial.cairo" "/artifacts/trivial" diff --git a/starknet-core/test-data/contracts/cairo2.6/docker_entry_hashes.sh b/starknet-core/test-data/contracts/cairo2.6/docker_entry_hashes.sh index c42c4cb5..ba0c8d2c 100755 --- a/starknet-core/test-data/contracts/cairo2.6/docker_entry_hashes.sh +++ b/starknet-core/test-data/contracts/cairo2.6/docker_entry_hashes.sh @@ -9,3 +9,4 @@ hash () { } hash "/artifacts/erc20" +hash "/artifacts/trivial" From dbe467e827bb7a02ff8e836cb08c9dd00b56f397 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 9 Sep 2024 22:11:58 -0700 Subject: [PATCH 35/54] feat: jsonrpc batch requests (#653) --- README.md | 16 +- examples/batch.rs | 36 ++ examples/parse_jsonrpc_request.rs | 4 +- starknet-providers/src/any.rs | 19 +- starknet-providers/src/jsonrpc/mod.rs | 372 +++++++++++++----- .../src/jsonrpc/transports/http.rs | 71 +++- .../src/jsonrpc/transports/mod.rs | 13 +- starknet-providers/src/lib.rs | 2 +- starknet-providers/src/provider.rs | 140 ++++++- starknet-providers/src/sequencer/provider.rs | 16 +- starknet-providers/tests/jsonrpc.rs | 45 ++- 11 files changed, 622 insertions(+), 112 deletions(-) create mode 100644 examples/batch.rs diff --git a/README.md b/README.md index ba8e58a1..3371af44 100644 --- a/README.md +++ b/README.md @@ -92,19 +92,21 @@ Examples can be found in the [examples folder](./examples): 6. [Query the latest block number with JSON-RPC](./examples/jsonrpc.rs) -7. [Call a contract view function](./examples/erc20_balance.rs) +7. [Batched JSON-RPC requests](./examples/batch.rs) -8. [Deploy an Argent X account to a pre-funded address](./examples/deploy_argent_account.rs) +8. [Call a contract view function](./examples/erc20_balance.rs) -9. [Inspect public key with Ledger](./examples/ledger_public_key.rs) +9. [Deploy an Argent X account to a pre-funded address](./examples/deploy_argent_account.rs) -10. [Deploy an OpenZeppelin account with Ledger](./examples/deploy_account_with_ledger.rs) +10. [Inspect public key with Ledger](./examples/ledger_public_key.rs) -11. [Transfer ERC20 tokens with Ledger](./examples/transfer_with_ledger.rs) +11. [Deploy an OpenZeppelin account with Ledger](./examples/deploy_account_with_ledger.rs) -12. [Parsing a JSON-RPC request on the server side](./examples/parse_jsonrpc_request.rs) +12. [Transfer ERC20 tokens with Ledger](./examples/transfer_with_ledger.rs) -13. [Inspecting a erased provider-specific error type](./examples/downcast_provider_error.rs) +13. [Parsing a JSON-RPC request on the server side](./examples/parse_jsonrpc_request.rs) + +14. [Inspecting a erased provider-specific error type](./examples/downcast_provider_error.rs) ## License diff --git a/examples/batch.rs b/examples/batch.rs new file mode 100644 index 00000000..5dc1b78a --- /dev/null +++ b/examples/batch.rs @@ -0,0 +1,36 @@ +use starknet::providers::{ + jsonrpc::{HttpTransport, JsonRpcClient}, + Provider, ProviderRequestData, ProviderResponseData, Url, +}; +use starknet_core::types::{ + requests::{BlockNumberRequest, GetBlockTransactionCountRequest}, + BlockId, +}; + +#[tokio::main] +async fn main() { + let provider = JsonRpcClient::new(HttpTransport::new( + Url::parse("https://starknet-sepolia.public.blastapi.io/rpc/v0_7").unwrap(), + )); + + let responses = provider + .batch_requests([ + ProviderRequestData::BlockNumber(BlockNumberRequest), + ProviderRequestData::GetBlockTransactionCount(GetBlockTransactionCountRequest { + block_id: BlockId::Number(100), + }), + ]) + .await + .unwrap(); + + match (&responses[0], &responses[1]) { + ( + ProviderResponseData::BlockNumber(block_number), + ProviderResponseData::GetBlockTransactionCount(count), + ) => { + println!("The latest block is #{}", block_number); + println!("Block #100 has {} transactions", count); + } + _ => panic!("unexpected response type"), + } +} diff --git a/examples/parse_jsonrpc_request.rs b/examples/parse_jsonrpc_request.rs index d325cf2c..6a69dd2a 100644 --- a/examples/parse_jsonrpc_request.rs +++ b/examples/parse_jsonrpc_request.rs @@ -1,4 +1,4 @@ -use starknet_providers::jsonrpc::{JsonRpcRequest, JsonRpcRequestData}; +use starknet_providers::{jsonrpc::JsonRpcRequest, ProviderRequestData}; fn main() { // Let's pretend this is the raw request body coming from HTTP @@ -17,7 +17,7 @@ fn main() { println!("Request received: {:#?}", parsed_request); match parsed_request.data { - JsonRpcRequestData::GetBlockTransactionCount(req) => { + ProviderRequestData::GetBlockTransactionCount(req) => { println!( "starknet_getBlockTransactionCount request received for block: {:?}", req.block_id diff --git a/starknet-providers/src/any.rs b/starknet-providers/src/any.rs index 5a10711f..3bc2b0ad 100644 --- a/starknet-providers/src/any.rs +++ b/starknet-providers/src/any.rs @@ -12,7 +12,7 @@ use starknet_core::types::{ use crate::{ jsonrpc::{HttpTransport, JsonRpcClient}, - Provider, ProviderError, SequencerGatewayProvider, + Provider, ProviderError, ProviderRequestData, ProviderResponseData, SequencerGatewayProvider, }; /// A convenient Box-able type that implements the [Provider] trait. This can be useful when you @@ -665,4 +665,21 @@ impl Provider for AnyProvider { } } } + + async fn batch_requests( + &self, + requests: R, + ) -> Result, ProviderError> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + match self { + Self::JsonRpcHttp(inner) => { + as Provider>::batch_requests(inner, requests).await + } + Self::SequencerGateway(inner) => { + ::batch_requests(inner, requests).await + } + } + } } diff --git a/starknet-providers/src/jsonrpc/mod.rs b/starknet-providers/src/jsonrpc/mod.rs index 2d6013ed..1f91e070 100644 --- a/starknet-providers/src/jsonrpc/mod.rs +++ b/starknet-providers/src/jsonrpc/mod.rs @@ -19,7 +19,9 @@ use starknet_core::{ }, }; -use crate::{provider::ProviderImplError, Provider, ProviderError}; +use crate::{ + provider::ProviderImplError, Provider, ProviderError, ProviderRequestData, ProviderResponseData, +}; mod transports; pub use transports::{HttpTransport, HttpTransportError, JsonRpcTransport}; @@ -131,70 +133,7 @@ pub struct JsonRpcRequest { /// ID of the request. Useful for identifying responses in certain transports like `WebSocket`. pub id: u64, /// Data of the requeest. - pub data: JsonRpcRequestData, -} - -/// Typed request data for Starknet JSON-RPC requests. -#[derive(Debug, Clone)] -pub enum JsonRpcRequestData { - /// Request data for `starknet_specVersion`. - SpecVersion(SpecVersionRequest), - /// Request data for `starknet_getBlockWithTxHashes`. - GetBlockWithTxHashes(GetBlockWithTxHashesRequest), - /// Request data for `starknet_getBlockWithTxs`. - GetBlockWithTxs(GetBlockWithTxsRequest), - /// Request data for `starknet_getBlockWithReceipts`. - GetBlockWithReceipts(GetBlockWithReceiptsRequest), - /// Request data for `starknet_getStateUpdate`. - GetStateUpdate(GetStateUpdateRequest), - /// Request data for `starknet_getStorageAt`. - GetStorageAt(GetStorageAtRequest), - /// Request data for `starknet_getTransactionStatus`. - GetTransactionStatus(GetTransactionStatusRequest), - /// Request data for `starknet_getTransactionByHash`. - GetTransactionByHash(GetTransactionByHashRequest), - /// Request data for `starknet_getTransactionByBlockIdAndIndex`. - GetTransactionByBlockIdAndIndex(GetTransactionByBlockIdAndIndexRequest), - /// Request data for `starknet_getTransactionReceipt`. - GetTransactionReceipt(GetTransactionReceiptRequest), - /// Request data for `starknet_getClass`. - GetClass(GetClassRequest), - /// Request data for `starknet_getClassHashAt`. - GetClassHashAt(GetClassHashAtRequest), - /// Request data for `starknet_getClassAt`. - GetClassAt(GetClassAtRequest), - /// Request data for `starknet_getBlockTransactionCount`. - GetBlockTransactionCount(GetBlockTransactionCountRequest), - /// Request data for `starknet_call`. - Call(CallRequest), - /// Request data for `starknet_estimateFee`. - EstimateFee(EstimateFeeRequest), - /// Request data for `starknet_estimateMessageFee`. - EstimateMessageFee(EstimateMessageFeeRequest), - /// Request data for `starknet_blockNumber`. - BlockNumber(BlockNumberRequest), - /// Request data for `starknet_blockHashAndNumber`. - BlockHashAndNumber(BlockHashAndNumberRequest), - /// Request data for `starknet_chainId`. - ChainId(ChainIdRequest), - /// Request data for `starknet_syncing`. - Syncing(SyncingRequest), - /// Request data for `starknet_getEvents`. - GetEvents(GetEventsRequest), - /// Request data for `starknet_getNonce`. - GetNonce(GetNonceRequest), - /// Request data for `starknet_addInvokeTransaction`. - AddInvokeTransaction(AddInvokeTransactionRequest), - /// Request data for `starknet_addDeclareTransaction`. - AddDeclareTransaction(AddDeclareTransactionRequest), - /// Request data for `starknet_addDeployAccountTransaction`. - AddDeployAccountTransaction(AddDeployAccountTransactionRequest), - /// Request data for `starknet_traceTransaction`. - TraceTransaction(TraceTransactionRequest), - /// Request data for `starknet_simulateTransactions`. - SimulateTransactions(SimulateTransactionsRequest), - /// Request data for `starknet_traceBlockTransactions`. - TraceBlockTransactions(TraceBlockTransactionsRequest), + pub data: ProviderRequestData, } /// Errors from JSON-RPC client. @@ -212,7 +151,7 @@ pub enum JsonRpcClientError { } /// An unsuccessful response returned from the server. -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Deserialize)] pub struct JsonRpcError { /// Error code. pub code: i64, @@ -224,7 +163,7 @@ pub struct JsonRpcError { } /// JSON-RPC response returned from a server. -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Deserialize)] #[serde(untagged)] pub enum JsonRpcResponse { /// Successful response. @@ -303,6 +242,199 @@ where } } } + + async fn send_requests( + &self, + requests: R, + ) -> Result, ProviderError> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + let mut results = vec![]; + + let responses = self + .transport + .send_requests(requests.as_ref().to_vec()) + .await + .map_err(JsonRpcClientError::TransportError)?; + + for (request, response) in requests.as_ref().iter().zip(responses.into_iter()) { + match response { + JsonRpcResponse::Success { result, .. } => { + let result = match request { + ProviderRequestData::SpecVersion(_) => ProviderResponseData::SpecVersion( + String::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ), + ProviderRequestData::GetBlockWithTxHashes(_) => { + ProviderResponseData::GetBlockWithTxHashes( + MaybePendingBlockWithTxHashes::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::GetBlockWithTxs(_) => { + ProviderResponseData::GetBlockWithTxs( + MaybePendingBlockWithTxs::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::GetBlockWithReceipts(_) => { + ProviderResponseData::GetBlockWithReceipts( + MaybePendingBlockWithReceipts::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::GetStateUpdate(_) => { + ProviderResponseData::GetStateUpdate( + MaybePendingStateUpdate::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::GetStorageAt(_) => ProviderResponseData::GetStorageAt( + Felt::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)? + .0, + ), + ProviderRequestData::GetTransactionStatus(_) => { + ProviderResponseData::GetTransactionStatus( + TransactionStatus::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::GetTransactionByHash(_) => { + ProviderResponseData::GetTransactionByHash( + Transaction::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::GetTransactionByBlockIdAndIndex(_) => { + ProviderResponseData::GetTransactionByBlockIdAndIndex( + Transaction::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::GetTransactionReceipt(_) => { + ProviderResponseData::GetTransactionReceipt( + TransactionReceiptWithBlockInfo::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::GetClass(_) => ProviderResponseData::GetClass( + ContractClass::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ), + ProviderRequestData::GetClassHashAt(_) => { + ProviderResponseData::GetClassHashAt( + Felt::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)? + .0, + ) + } + ProviderRequestData::GetClassAt(_) => ProviderResponseData::GetClassAt( + ContractClass::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ), + ProviderRequestData::GetBlockTransactionCount(_) => { + ProviderResponseData::GetBlockTransactionCount( + u64::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::Call(_) => ProviderResponseData::Call( + FeltArray::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)? + .0, + ), + ProviderRequestData::EstimateFee(_) => ProviderResponseData::EstimateFee( + Vec::::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ), + ProviderRequestData::EstimateMessageFee(_) => { + ProviderResponseData::EstimateMessageFee( + FeeEstimate::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::BlockNumber(_) => ProviderResponseData::BlockNumber( + u64::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ), + ProviderRequestData::BlockHashAndNumber(_) => { + ProviderResponseData::BlockHashAndNumber( + BlockHashAndNumber::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::ChainId(_) => ProviderResponseData::ChainId( + Felt::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)? + .0, + ), + ProviderRequestData::Syncing(_) => ProviderResponseData::Syncing( + SyncStatusType::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ), + ProviderRequestData::GetEvents(_) => ProviderResponseData::GetEvents( + EventsPage::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ), + ProviderRequestData::GetNonce(_) => ProviderResponseData::GetNonce( + Felt::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)? + .0, + ), + ProviderRequestData::AddInvokeTransaction(_) => { + ProviderResponseData::AddInvokeTransaction( + InvokeTransactionResult::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::AddDeclareTransaction(_) => { + ProviderResponseData::AddDeclareTransaction( + DeclareTransactionResult::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::AddDeployAccountTransaction(_) => { + ProviderResponseData::AddDeployAccountTransaction( + DeployAccountTransactionResult::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::TraceTransaction(_) => { + ProviderResponseData::TraceTransaction( + TransactionTrace::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::SimulateTransactions(_) => { + ProviderResponseData::SimulateTransactions( + Vec::::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + ProviderRequestData::TraceBlockTransactions(_) => { + ProviderResponseData::TraceBlockTransactions( + Vec::::deserialize(result) + .map_err(JsonRpcClientError::::JsonError)?, + ) + } + }; + + results.push(result); + } + // TODO: add context on index of request causing the error + JsonRpcResponse::Error { error, .. } => { + return Err(match TryInto::::try_into(&error) { + Ok(error) => ProviderError::StarknetError(error), + Err(_) => JsonRpcClientError::::JsonRpcError(error).into(), + }) + } + } + } + + Ok(results) + } } #[cfg_attr(not(target_arch = "wasm32"), async_trait)] @@ -801,6 +933,54 @@ where ) .await } + + async fn batch_requests( + &self, + requests: R, + ) -> Result, ProviderError> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + self.send_requests(requests).await + } +} + +impl ProviderRequestData { + const fn jsonrpc_method(&self) -> JsonRpcMethod { + match self { + Self::SpecVersion(_) => JsonRpcMethod::SpecVersion, + Self::GetBlockWithTxHashes(_) => JsonRpcMethod::GetBlockWithTxHashes, + Self::GetBlockWithTxs(_) => JsonRpcMethod::GetBlockWithTxs, + Self::GetBlockWithReceipts(_) => JsonRpcMethod::GetBlockWithReceipts, + Self::GetStateUpdate(_) => JsonRpcMethod::GetStateUpdate, + Self::GetStorageAt(_) => JsonRpcMethod::GetStorageAt, + Self::GetTransactionStatus(_) => JsonRpcMethod::GetTransactionStatus, + Self::GetTransactionByHash(_) => JsonRpcMethod::GetTransactionByHash, + Self::GetTransactionByBlockIdAndIndex(_) => { + JsonRpcMethod::GetTransactionByBlockIdAndIndex + } + Self::GetTransactionReceipt(_) => JsonRpcMethod::GetTransactionReceipt, + Self::GetClass(_) => JsonRpcMethod::GetClass, + Self::GetClassHashAt(_) => JsonRpcMethod::GetClassHashAt, + Self::GetClassAt(_) => JsonRpcMethod::GetClassAt, + Self::GetBlockTransactionCount(_) => JsonRpcMethod::GetBlockTransactionCount, + Self::Call(_) => JsonRpcMethod::Call, + Self::EstimateFee(_) => JsonRpcMethod::EstimateFee, + Self::EstimateMessageFee(_) => JsonRpcMethod::EstimateMessageFee, + Self::BlockNumber(_) => JsonRpcMethod::BlockNumber, + Self::BlockHashAndNumber(_) => JsonRpcMethod::BlockHashAndNumber, + Self::ChainId(_) => JsonRpcMethod::ChainId, + Self::Syncing(_) => JsonRpcMethod::Syncing, + Self::GetEvents(_) => JsonRpcMethod::GetEvents, + Self::GetNonce(_) => JsonRpcMethod::GetNonce, + Self::AddInvokeTransaction(_) => JsonRpcMethod::AddInvokeTransaction, + Self::AddDeclareTransaction(_) => JsonRpcMethod::AddDeclareTransaction, + Self::AddDeployAccountTransaction(_) => JsonRpcMethod::AddDeployAccountTransaction, + Self::TraceTransaction(_) => JsonRpcMethod::TraceTransaction, + Self::SimulateTransactions(_) => JsonRpcMethod::SimulateTransactions, + Self::TraceBlockTransactions(_) => JsonRpcMethod::TraceBlockTransactions, + } + } } impl<'de> Deserialize<'de> for JsonRpcRequest { @@ -820,128 +1000,128 @@ impl<'de> Deserialize<'de> for JsonRpcRequest { let raw_request = RawRequest::deserialize(deserializer)?; let request_data = match raw_request.method { - JsonRpcMethod::SpecVersion => JsonRpcRequestData::SpecVersion( + JsonRpcMethod::SpecVersion => ProviderRequestData::SpecVersion( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::GetBlockWithTxHashes => JsonRpcRequestData::GetBlockWithTxHashes( + JsonRpcMethod::GetBlockWithTxHashes => ProviderRequestData::GetBlockWithTxHashes( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::GetBlockWithTxs => JsonRpcRequestData::GetBlockWithTxs( + JsonRpcMethod::GetBlockWithTxs => ProviderRequestData::GetBlockWithTxs( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::GetBlockWithReceipts => JsonRpcRequestData::GetBlockWithReceipts( + JsonRpcMethod::GetBlockWithReceipts => ProviderRequestData::GetBlockWithReceipts( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::GetStateUpdate => JsonRpcRequestData::GetStateUpdate( + JsonRpcMethod::GetStateUpdate => ProviderRequestData::GetStateUpdate( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::GetStorageAt => JsonRpcRequestData::GetStorageAt( + JsonRpcMethod::GetStorageAt => ProviderRequestData::GetStorageAt( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::GetTransactionStatus => JsonRpcRequestData::GetTransactionStatus( + JsonRpcMethod::GetTransactionStatus => ProviderRequestData::GetTransactionStatus( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::GetTransactionByHash => JsonRpcRequestData::GetTransactionByHash( + JsonRpcMethod::GetTransactionByHash => ProviderRequestData::GetTransactionByHash( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), JsonRpcMethod::GetTransactionByBlockIdAndIndex => { - JsonRpcRequestData::GetTransactionByBlockIdAndIndex( + ProviderRequestData::GetTransactionByBlockIdAndIndex( serde_json::from_value::( raw_request.params, ) .map_err(error_mapper)?, ) } - JsonRpcMethod::GetTransactionReceipt => JsonRpcRequestData::GetTransactionReceipt( + JsonRpcMethod::GetTransactionReceipt => ProviderRequestData::GetTransactionReceipt( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::GetClass => JsonRpcRequestData::GetClass( + JsonRpcMethod::GetClass => ProviderRequestData::GetClass( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::GetClassHashAt => JsonRpcRequestData::GetClassHashAt( + JsonRpcMethod::GetClassHashAt => ProviderRequestData::GetClassHashAt( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::GetClassAt => JsonRpcRequestData::GetClassAt( + JsonRpcMethod::GetClassAt => ProviderRequestData::GetClassAt( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), JsonRpcMethod::GetBlockTransactionCount => { - JsonRpcRequestData::GetBlockTransactionCount( + ProviderRequestData::GetBlockTransactionCount( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ) } - JsonRpcMethod::Call => JsonRpcRequestData::Call( + JsonRpcMethod::Call => ProviderRequestData::Call( serde_json::from_value::(raw_request.params).map_err(error_mapper)?, ), - JsonRpcMethod::EstimateFee => JsonRpcRequestData::EstimateFee( + JsonRpcMethod::EstimateFee => ProviderRequestData::EstimateFee( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::EstimateMessageFee => JsonRpcRequestData::EstimateMessageFee( + JsonRpcMethod::EstimateMessageFee => ProviderRequestData::EstimateMessageFee( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::BlockNumber => JsonRpcRequestData::BlockNumber( + JsonRpcMethod::BlockNumber => ProviderRequestData::BlockNumber( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::BlockHashAndNumber => JsonRpcRequestData::BlockHashAndNumber( + JsonRpcMethod::BlockHashAndNumber => ProviderRequestData::BlockHashAndNumber( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::ChainId => JsonRpcRequestData::ChainId( + JsonRpcMethod::ChainId => ProviderRequestData::ChainId( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::Syncing => JsonRpcRequestData::Syncing( + JsonRpcMethod::Syncing => ProviderRequestData::Syncing( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::GetEvents => JsonRpcRequestData::GetEvents( + JsonRpcMethod::GetEvents => ProviderRequestData::GetEvents( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::GetNonce => JsonRpcRequestData::GetNonce( + JsonRpcMethod::GetNonce => ProviderRequestData::GetNonce( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::AddInvokeTransaction => JsonRpcRequestData::AddInvokeTransaction( + JsonRpcMethod::AddInvokeTransaction => ProviderRequestData::AddInvokeTransaction( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::AddDeclareTransaction => JsonRpcRequestData::AddDeclareTransaction( + JsonRpcMethod::AddDeclareTransaction => ProviderRequestData::AddDeclareTransaction( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), JsonRpcMethod::AddDeployAccountTransaction => { - JsonRpcRequestData::AddDeployAccountTransaction( + ProviderRequestData::AddDeployAccountTransaction( serde_json::from_value::( raw_request.params, ) .map_err(error_mapper)?, ) } - JsonRpcMethod::TraceTransaction => JsonRpcRequestData::TraceTransaction( + JsonRpcMethod::TraceTransaction => ProviderRequestData::TraceTransaction( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::SimulateTransactions => JsonRpcRequestData::SimulateTransactions( + JsonRpcMethod::SimulateTransactions => ProviderRequestData::SimulateTransactions( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), - JsonRpcMethod::TraceBlockTransactions => JsonRpcRequestData::TraceBlockTransactions( + JsonRpcMethod::TraceBlockTransactions => ProviderRequestData::TraceBlockTransactions( serde_json::from_value::(raw_request.params) .map_err(error_mapper)?, ), diff --git a/starknet-providers/src/jsonrpc/transports/http.rs b/starknet-providers/src/jsonrpc/transports/http.rs index 4663b859..bf85ca0f 100644 --- a/starknet-providers/src/jsonrpc/transports/http.rs +++ b/starknet-providers/src/jsonrpc/transports/http.rs @@ -3,7 +3,10 @@ use log::trace; use reqwest::{Client, Url}; use serde::{de::DeserializeOwned, Serialize}; -use crate::jsonrpc::{transports::JsonRpcTransport, JsonRpcMethod, JsonRpcResponse}; +use crate::{ + jsonrpc::{transports::JsonRpcTransport, JsonRpcMethod, JsonRpcResponse}, + ProviderRequestData, +}; /// A [`JsonRpcTransport`] implementation that uses HTTP connections. #[derive(Debug)] @@ -21,6 +24,9 @@ pub enum HttpTransportError { Reqwest(reqwest::Error), /// JSON serialization/deserialization errors. Json(serde_json::Error), + /// Unexpected response ID. + #[error("unexpected response ID: {0}")] + UnexpectedResponseId(u64), } #[derive(Debug, Serialize)] @@ -110,4 +116,67 @@ impl JsonRpcTransport for HttpTransport { Ok(parsed_response) } + + async fn send_requests( + &self, + requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + let request_bodies = requests + .as_ref() + .iter() + .enumerate() + .map(|(ind, request)| JsonRpcRequest { + id: ind as u64, + jsonrpc: "2.0", + method: request.jsonrpc_method(), + params: request, + }) + .collect::>(); + + let request_count = request_bodies.len(); + + let request_body = serde_json::to_string(&request_bodies).map_err(Self::Error::Json)?; + trace!("Sending request via JSON-RPC: {}", request_body); + + let mut request = self + .client + .post(self.url.clone()) + .body(request_body) + .header("Content-Type", "application/json"); + for (name, value) in &self.headers { + request = request.header(name, value); + } + + let response = request.send().await.map_err(Self::Error::Reqwest)?; + + let response_body = response.text().await.map_err(Self::Error::Reqwest)?; + trace!("Response from JSON-RPC: {}", response_body); + + let parsed_response: Vec> = + serde_json::from_str(&response_body).map_err(Self::Error::Json)?; + + let mut responses: Vec>> = vec![]; + responses.resize(request_bodies.len(), None); + + // Re-order the responses as servers do not maintain order. + for response_item in parsed_response { + let id = match &response_item { + JsonRpcResponse::Success { id, .. } | JsonRpcResponse::Error { id, .. } => { + *id as usize + } + }; + + if id >= request_count { + return Err(HttpTransportError::UnexpectedResponseId(id as u64)); + } + + responses[id] = Some(response_item); + } + + let responses = responses.into_iter().flatten().collect::>(); + Ok(responses) + } } diff --git a/starknet-providers/src/jsonrpc/transports/mod.rs b/starknet-providers/src/jsonrpc/transports/mod.rs index c7602c98..3c172c11 100644 --- a/starknet-providers/src/jsonrpc/transports/mod.rs +++ b/starknet-providers/src/jsonrpc/transports/mod.rs @@ -3,7 +3,10 @@ use auto_impl::auto_impl; use serde::{de::DeserializeOwned, Serialize}; use std::error::Error; -use crate::jsonrpc::{JsonRpcMethod, JsonRpcResponse}; +use crate::{ + jsonrpc::{JsonRpcMethod, JsonRpcResponse}, + ProviderRequestData, +}; mod http; pub use http::{HttpTransport, HttpTransportError}; @@ -26,4 +29,12 @@ pub trait JsonRpcTransport { where P: Serialize + Send + Sync, R: DeserializeOwned; + + /// Sends multiple JSON-RPC requests in parallel. + async fn send_requests( + &self, + requests: R, + ) -> Result>, Self::Error> + where + R: AsRef<[ProviderRequestData]> + Send + Sync; } diff --git a/starknet-providers/src/lib.rs b/starknet-providers/src/lib.rs index 0954c3d2..a8392dd3 100644 --- a/starknet-providers/src/lib.rs +++ b/starknet-providers/src/lib.rs @@ -7,7 +7,7 @@ #![deny(missing_docs)] mod provider; -pub use provider::{Provider, ProviderError}; +pub use provider::{Provider, ProviderError, ProviderRequestData, ProviderResponseData}; // Sequencer-related functionalities are mostly deprecated so we skip the docs. /// Module containing types related to the (now deprecated) sequencer gateway client. diff --git a/starknet-providers/src/provider.rs b/starknet-providers/src/provider.rs index 94d853c3..f513e52c 100644 --- a/starknet-providers/src/provider.rs +++ b/starknet-providers/src/provider.rs @@ -1,7 +1,8 @@ use async_trait::async_trait; use auto_impl::auto_impl; +use serde::Serialize; use starknet_core::types::{ - BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction, + requests::*, BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction, BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, BroadcastedTransaction, ContractClass, DeclareTransactionResult, DeployAccountTransactionResult, EventFilter, EventsPage, FeeEstimate, Felt, FunctionCall, InvokeTransactionResult, @@ -260,6 +261,15 @@ pub trait Provider { where B: AsRef + Send + Sync; + /// Sends multiple requests in parallel. The function call fails if any of the requests fails. + /// Implementations must guarantee that responses follow the exact order as the requests. + async fn batch_requests( + &self, + requests: R, + ) -> Result, ProviderError> + where + R: AsRef<[ProviderRequestData]> + Send + Sync; + /// Same as [`estimate_fee`](fn.estimate_fee), but only with one estimate. async fn estimate_fee_single( &self, @@ -350,3 +360,131 @@ pub enum ProviderError { #[error("{0}")] Other(Box), } + +/// Typed request data for [`Provider`] requests. +#[derive(Debug, Clone, Serialize)] +#[serde(untagged)] +pub enum ProviderRequestData { + /// Request data for `starknet_specVersion`. + SpecVersion(SpecVersionRequest), + /// Request data for `starknet_getBlockWithTxHashes`. + GetBlockWithTxHashes(GetBlockWithTxHashesRequest), + /// Request data for `starknet_getBlockWithTxs`. + GetBlockWithTxs(GetBlockWithTxsRequest), + /// Request data for `starknet_getBlockWithReceipts`. + GetBlockWithReceipts(GetBlockWithReceiptsRequest), + /// Request data for `starknet_getStateUpdate`. + GetStateUpdate(GetStateUpdateRequest), + /// Request data for `starknet_getStorageAt`. + GetStorageAt(GetStorageAtRequest), + /// Request data for `starknet_getTransactionStatus`. + GetTransactionStatus(GetTransactionStatusRequest), + /// Request data for `starknet_getTransactionByHash`. + GetTransactionByHash(GetTransactionByHashRequest), + /// Request data for `starknet_getTransactionByBlockIdAndIndex`. + GetTransactionByBlockIdAndIndex(GetTransactionByBlockIdAndIndexRequest), + /// Request data for `starknet_getTransactionReceipt`. + GetTransactionReceipt(GetTransactionReceiptRequest), + /// Request data for `starknet_getClass`. + GetClass(GetClassRequest), + /// Request data for `starknet_getClassHashAt`. + GetClassHashAt(GetClassHashAtRequest), + /// Request data for `starknet_getClassAt`. + GetClassAt(GetClassAtRequest), + /// Request data for `starknet_getBlockTransactionCount`. + GetBlockTransactionCount(GetBlockTransactionCountRequest), + /// Request data for `starknet_call`. + Call(CallRequest), + /// Request data for `starknet_estimateFee`. + EstimateFee(EstimateFeeRequest), + /// Request data for `starknet_estimateMessageFee`. + EstimateMessageFee(EstimateMessageFeeRequest), + /// Request data for `starknet_blockNumber`. + BlockNumber(BlockNumberRequest), + /// Request data for `starknet_blockHashAndNumber`. + BlockHashAndNumber(BlockHashAndNumberRequest), + /// Request data for `starknet_chainId`. + ChainId(ChainIdRequest), + /// Request data for `starknet_syncing`. + Syncing(SyncingRequest), + /// Request data for `starknet_getEvents`. + GetEvents(GetEventsRequest), + /// Request data for `starknet_getNonce`. + GetNonce(GetNonceRequest), + /// Request data for `starknet_addInvokeTransaction`. + AddInvokeTransaction(AddInvokeTransactionRequest), + /// Request data for `starknet_addDeclareTransaction`. + AddDeclareTransaction(AddDeclareTransactionRequest), + /// Request data for `starknet_addDeployAccountTransaction`. + AddDeployAccountTransaction(AddDeployAccountTransactionRequest), + /// Request data for `starknet_traceTransaction`. + TraceTransaction(TraceTransactionRequest), + /// Request data for `starknet_simulateTransactions`. + SimulateTransactions(SimulateTransactionsRequest), + /// Request data for `starknet_traceBlockTransactions`. + TraceBlockTransactions(TraceBlockTransactionsRequest), +} + +/// Typed response data for [`Provider`] responses. +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone)] +pub enum ProviderResponseData { + /// Response data for `starknet_specVersion`. + SpecVersion(String), + /// Response data for `starknet_getBlockWithTxHashes`. + GetBlockWithTxHashes(MaybePendingBlockWithTxHashes), + /// Response data for `starknet_getBlockWithTxs`. + GetBlockWithTxs(MaybePendingBlockWithTxs), + /// Response data for `starknet_getBlockWithReceipts`. + GetBlockWithReceipts(MaybePendingBlockWithReceipts), + /// Response data for `starknet_getStateUpdate`. + GetStateUpdate(MaybePendingStateUpdate), + /// Response data for `starknet_getStorageAt`. + GetStorageAt(Felt), + /// Response data for `starknet_getTransactionStatus`. + GetTransactionStatus(TransactionStatus), + /// Response data for `starknet_getTransactionByHash`. + GetTransactionByHash(Transaction), + /// Response data for `starknet_getTransactionByBlockIdAndIndex`. + GetTransactionByBlockIdAndIndex(Transaction), + /// Response data for `starknet_getTransactionReceipt`. + GetTransactionReceipt(TransactionReceiptWithBlockInfo), + /// Response data for `starknet_getClass`. + GetClass(ContractClass), + /// Response data for `starknet_getClassHashAt`. + GetClassHashAt(Felt), + /// Response data for `starknet_getClassAt`. + GetClassAt(ContractClass), + /// Response data for `starknet_getBlockTransactionCount`. + GetBlockTransactionCount(u64), + /// Response data for `starknet_call`. + Call(Vec), + /// Response data for `starknet_estimateFee`. + EstimateFee(Vec), + /// Response data for `starknet_estimateMessageFee`. + EstimateMessageFee(FeeEstimate), + /// Response data for `starknet_blockNumber`. + BlockNumber(u64), + /// Response data for `starknet_blockHashAndNumber`. + BlockHashAndNumber(BlockHashAndNumber), + /// Response data for `starknet_chainId`. + ChainId(Felt), + /// Response data for `starknet_syncing`. + Syncing(SyncStatusType), + /// Response data for `starknet_getEvents`. + GetEvents(EventsPage), + /// Response data for `starknet_getNonce`. + GetNonce(Felt), + /// Response data for `starknet_addInvokeTransaction`. + AddInvokeTransaction(InvokeTransactionResult), + /// Response data for `starknet_addDeclareTransaction`. + AddDeclareTransaction(DeclareTransactionResult), + /// Response data for `starknet_addDeployAccountTransaction`. + AddDeployAccountTransaction(DeployAccountTransactionResult), + /// Response data for `starknet_traceTransaction`. + TraceTransaction(TransactionTrace), + /// Response data for `starknet_simulateTransactions`. + SimulateTransactions(Vec), + /// Response data for `starknet_traceBlockTransactions`. + TraceBlockTransactions(Vec), +} diff --git a/starknet-providers/src/sequencer/provider.rs b/starknet-providers/src/sequencer/provider.rs index 313cda9c..b046838b 100644 --- a/starknet-providers/src/sequencer/provider.rs +++ b/starknet-providers/src/sequencer/provider.rs @@ -17,7 +17,7 @@ use starknet_core::types::{ use crate::{ provider::ProviderImplError, sequencer::{models::conversions::ConversionError, GatewayClientError}, - Provider, ProviderError, SequencerGatewayProvider, + Provider, ProviderError, ProviderRequestData, ProviderResponseData, SequencerGatewayProvider, }; use super::models::TransactionFinalityStatus; @@ -414,6 +414,20 @@ impl Provider for SequencerGatewayProvider { GatewayClientError::MethodNotSupported, ))) } + + async fn batch_requests( + &self, + requests: R, + ) -> Result, ProviderError> + where + R: AsRef<[ProviderRequestData]> + Send + Sync, + { + // Not implemented for now. It's technically possible to simulate this by running multiple + // requests in parallel. + Err(ProviderError::Other(Box::new( + GatewayClientError::MethodNotSupported, + ))) + } } impl ProviderImplError for GatewayClientError { diff --git a/starknet-providers/tests/jsonrpc.rs b/starknet-providers/tests/jsonrpc.rs index dac0910a..ba813fae 100644 --- a/starknet-providers/tests/jsonrpc.rs +++ b/starknet-providers/tests/jsonrpc.rs @@ -1,5 +1,6 @@ use starknet_core::{ types::{ + requests::{CallRequest, GetBlockTransactionCountRequest}, BlockId, BlockTag, BroadcastedInvokeTransaction, BroadcastedInvokeTransactionV1, BroadcastedTransaction, ContractClass, DeclareTransaction, DeployAccountTransaction, EthAddress, EventFilter, ExecuteInvocation, ExecutionResult, Felt, FunctionCall, @@ -12,7 +13,7 @@ use starknet_core::{ }; use starknet_providers::{ jsonrpc::{HttpTransport, JsonRpcClient}, - Provider, ProviderError, + Provider, ProviderError, ProviderRequestData, ProviderResponseData, }; use url::Url; @@ -873,6 +874,48 @@ async fn jsonrpc_trace_deploy_account() { } } +#[tokio::test] +async fn jsonrpc_batch() { + let rpc_client = create_jsonrpc_client(); + + let responses = rpc_client + .batch_requests([ + ProviderRequestData::GetBlockTransactionCount(GetBlockTransactionCountRequest { + block_id: BlockId::Number(20_000), + }), + ProviderRequestData::Call(CallRequest { + request: FunctionCall { + contract_address: Felt::from_hex( + "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + ) + .unwrap(), + entry_point_selector: get_selector_from_name("balanceOf").unwrap(), + calldata: vec![Felt::from_hex( + "03f47d3911396b6d579fd7848cf576286ab6f96dda977915d6c7b10f3dd2315b", + ) + .unwrap()], + }, + block_id: BlockId::Tag(BlockTag::Latest), + }), + ]) + .await + .unwrap(); + + match &responses[0] { + ProviderResponseData::GetBlockTransactionCount(count) => { + assert_eq!(*count, 6); + } + _ => panic!("unexpected response type"), + } + + match &responses[1] { + ProviderResponseData::Call(eth_balance) => { + assert!(eth_balance[0] > Felt::ZERO); + } + _ => panic!("unexpected response type"), + } +} + // NOTE: `addXxxxTransaction` methods are harder to test here since they require signatures. These // are integration tests anyways, so we might as well just leave the job to th tests in // `starknet-accounts`. From c18f777481fe88384737aa3cb422319e8c3d8714 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Wed, 18 Sep 2024 11:16:15 +0800 Subject: [PATCH 36/54] chore: add `poseidon_permute_comp` back (#654) --- starknet-crypto/src/lib.rs | 4 +++- starknet-crypto/src/poseidon_hash.rs | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/starknet-crypto/src/lib.rs b/starknet-crypto/src/lib.rs index 321f4e5f..ce10c1f3 100644 --- a/starknet-crypto/src/lib.rs +++ b/starknet-crypto/src/lib.rs @@ -35,7 +35,9 @@ pub use starknet_types_core::felt::Felt; pub use pedersen_hash::pedersen_hash; -pub use poseidon_hash::{poseidon_hash, poseidon_hash_many, poseidon_hash_single, PoseidonHasher}; +pub use poseidon_hash::{ + poseidon_hash, poseidon_hash_many, poseidon_hash_single, poseidon_permute_comp, PoseidonHasher, +}; pub use ecdsa::{get_public_key, recover, sign, verify, ExtendedSignature, Signature}; diff --git a/starknet-crypto/src/poseidon_hash.rs b/starknet-crypto/src/poseidon_hash.rs index 4155f056..ff557ded 100644 --- a/starknet-crypto/src/poseidon_hash.rs +++ b/starknet-crypto/src/poseidon_hash.rs @@ -97,6 +97,11 @@ pub fn poseidon_hash_many<'a, I: IntoIterator>(msgs: I) -> Felt state[0] } +/// Poseidon permutation function. +pub fn poseidon_permute_comp(state: &mut [Felt; 3]) { + Poseidon::hades_permutation(state) +} + #[cfg(test)] mod tests { use starknet_types_core::hash::StarkHash; From ee9a5cdd678a3f1941599136432a1502ef772c00 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Wed, 18 Sep 2024 11:51:55 +0800 Subject: [PATCH 37/54] release: bump starknet to 0.12.0 (and deps) (#655) --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 18 +++++++++--------- examples/starknet-wasm/Cargo.toml | 2 +- starknet-accounts/Cargo.toml | 10 +++++----- starknet-contract/Cargo.toml | 10 +++++----- starknet-core/Cargo.toml | 4 ++-- starknet-crypto/Cargo.toml | 4 ++-- starknet-curve/Cargo.toml | 2 +- starknet-macros/Cargo.toml | 4 ++-- starknet-providers/Cargo.toml | 4 ++-- starknet-signers/Cargo.toml | 6 +++--- 11 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7841ce2e..c22a7bfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2020,7 +2020,7 @@ dependencies = [ [[package]] name = "starknet" -version = "0.11.0" +version = "0.12.0" dependencies = [ "serde_json", "starknet-accounts", @@ -2036,7 +2036,7 @@ dependencies = [ [[package]] name = "starknet-accounts" -version = "0.10.0" +version = "0.11.0" dependencies = [ "async-trait", "auto_impl", @@ -2053,7 +2053,7 @@ dependencies = [ [[package]] name = "starknet-contract" -version = "0.10.0" +version = "0.11.0" dependencies = [ "rand", "serde", @@ -2070,7 +2070,7 @@ dependencies = [ [[package]] name = "starknet-core" -version = "0.11.1" +version = "0.12.0" dependencies = [ "base64 0.21.0", "bincode", @@ -2092,7 +2092,7 @@ dependencies = [ [[package]] name = "starknet-crypto" -version = "0.7.1" +version = "0.7.2" dependencies = [ "criterion", "crypto-bigint", @@ -2114,7 +2114,7 @@ dependencies = [ [[package]] name = "starknet-curve" -version = "0.5.0" +version = "0.5.1" dependencies = [ "starknet-types-core", ] @@ -2131,7 +2131,7 @@ dependencies = [ [[package]] name = "starknet-macros" -version = "0.2.0" +version = "0.2.1" dependencies = [ "starknet-core", "syn 2.0.63", @@ -2139,7 +2139,7 @@ dependencies = [ [[package]] name = "starknet-providers" -version = "0.11.0" +version = "0.12.0" dependencies = [ "async-trait", "auto_impl", @@ -2160,7 +2160,7 @@ dependencies = [ [[package]] name = "starknet-signers" -version = "0.9.0" +version = "0.10.0" dependencies = [ "async-trait", "auto_impl", diff --git a/Cargo.toml b/Cargo.toml index 9e09d340..831cc42a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet" -version = "0.11.0" +version = "0.12.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -32,17 +32,17 @@ members = [ all-features = true [dependencies] -starknet-crypto = { version = "0.7.1", path = "./starknet-crypto" } -starknet-core = { version = "0.11.1", path = "./starknet-core", default-features = false } -starknet-providers = { version = "0.11.0", path = "./starknet-providers" } -starknet-contract = { version = "0.10.0", path = "./starknet-contract" } -starknet-signers = { version = "0.9.0", path = "./starknet-signers" } -starknet-accounts = { version = "0.10.0", path = "./starknet-accounts" } -starknet-macros = { version = "0.2.0", path = "./starknet-macros" } +starknet-crypto = { version = "0.7.2", path = "./starknet-crypto" } +starknet-core = { version = "0.12.0", path = "./starknet-core", default-features = false } +starknet-providers = { version = "0.12.0", path = "./starknet-providers" } +starknet-contract = { version = "0.11.0", path = "./starknet-contract" } +starknet-signers = { version = "0.10.0", path = "./starknet-signers" } +starknet-accounts = { version = "0.11.0", path = "./starknet-accounts" } +starknet-macros = { version = "0.2.1", path = "./starknet-macros" } [dev-dependencies] serde_json = "1.0.74" -starknet-signers = { version = "0.9.0", path = "./starknet-signers", features = ["ledger"] } +starknet-signers = { version = "0.10.0", path = "./starknet-signers", features = ["ledger"] } tokio = { version = "1.15.0", features = ["full"] } url = "2.2.2" diff --git a/examples/starknet-wasm/Cargo.toml b/examples/starknet-wasm/Cargo.toml index 2ec65513..15c061bf 100644 --- a/examples/starknet-wasm/Cargo.toml +++ b/examples/starknet-wasm/Cargo.toml @@ -19,6 +19,6 @@ crate-type = ["cdylib", "rlib"] default = ["console_error_panic_hook"] [dependencies] -starknet-crypto = { version = "0.7.1", path = "../../starknet-crypto" } +starknet-crypto = { version = "0.7.2", path = "../../starknet-crypto" } console_error_panic_hook = { version = "0.1.7", optional = true } wasm-bindgen = "0.2.84" diff --git a/starknet-accounts/Cargo.toml b/starknet-accounts/Cargo.toml index 442a53fe..d7a9828f 100644 --- a/starknet-accounts/Cargo.toml +++ b/starknet-accounts/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-accounts" -version = "0.10.0" +version = "0.11.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -14,10 +14,10 @@ keywords = ["ethereum", "starknet", "web3"] exclude = ["test-data/**"] [dependencies] -starknet-core = { version = "0.11.1", path = "../starknet-core" } -starknet-crypto = { version = "0.7.1", path = "../starknet-crypto" } -starknet-providers = { version = "0.11.0", path = "../starknet-providers" } -starknet-signers = { version = "0.9.0", path = "../starknet-signers" } +starknet-core = { version = "0.12.0", path = "../starknet-core" } +starknet-crypto = { version = "0.7.2", path = "../starknet-crypto" } +starknet-providers = { version = "0.12.0", path = "../starknet-providers" } +starknet-signers = { version = "0.10.0", path = "../starknet-signers" } async-trait = "0.1.68" auto_impl = "1.0.1" thiserror = "1.0.40" diff --git a/starknet-contract/Cargo.toml b/starknet-contract/Cargo.toml index f6a89f3c..82ac3cbc 100644 --- a/starknet-contract/Cargo.toml +++ b/starknet-contract/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-contract" -version = "0.10.0" +version = "0.11.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -14,9 +14,9 @@ keywords = ["ethereum", "starknet", "web3"] exclude = ["test-data/**"] [dependencies] -starknet-core = { version = "0.11.1", path = "../starknet-core" } -starknet-providers = { version = "0.11.0", path = "../starknet-providers" } -starknet-accounts = { version = "0.10.0", path = "../starknet-accounts" } +starknet-core = { version = "0.12.0", path = "../starknet-core" } +starknet-providers = { version = "0.12.0", path = "../starknet-providers" } +starknet-accounts = { version = "0.11.0", path = "../starknet-accounts" } serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0.96" serde_with = "3.9.0" @@ -24,7 +24,7 @@ thiserror = "1.0.40" [dev-dependencies] rand = { version = "0.8.5", features=["std_rng"] } -starknet-signers = { version = "0.9.0", path = "../starknet-signers" } +starknet-signers = { version = "0.10.0", path = "../starknet-signers" } tokio = { version = "1.27.0", features = ["full"] } url = "2.3.1" diff --git a/starknet-core/Cargo.toml b/starknet-core/Cargo.toml index 363ca0c7..41f74908 100644 --- a/starknet-core/Cargo.toml +++ b/starknet-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-core" -version = "0.11.1" +version = "0.12.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -17,7 +17,7 @@ exclude = ["test-data/**"] all-features = true [dependencies] -starknet-crypto = { version = "0.7.1", path = "../starknet-crypto", default-features = false, features = ["alloc"] } +starknet-crypto = { version = "0.7.2", path = "../starknet-crypto", default-features = false, features = ["alloc"] } base64 = { version = "0.21.0", default-features = false, features = ["alloc"] } crypto-bigint = { version = "0.5.1", default-features = false } flate2 = { version = "1.0.25", optional = true } diff --git a/starknet-crypto/Cargo.toml b/starknet-crypto/Cargo.toml index 29164d2a..52c23b5b 100644 --- a/starknet-crypto/Cargo.toml +++ b/starknet-crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-crypto" -version = "0.7.1" +version = "0.7.2" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -14,7 +14,7 @@ keywords = ["ethereum", "starknet", "web3", "no_std"] exclude = ["test-data/**"] [dependencies] -starknet-curve = { version = "0.5.0", path = "../starknet-curve" } +starknet-curve = { version = "0.5.1", path = "../starknet-curve" } crypto-bigint = { version = "0.5.1", default-features = false, features = ["generic-array", "zeroize"] } hmac = { version = "0.12.1", default-features = false } num-bigint = { version = "0.4.3", default-features = false } diff --git a/starknet-curve/Cargo.toml b/starknet-curve/Cargo.toml index 7c01748b..ee2f084e 100644 --- a/starknet-curve/Cargo.toml +++ b/starknet-curve/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-curve" -version = "0.5.0" +version = "0.5.1" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" diff --git a/starknet-macros/Cargo.toml b/starknet-macros/Cargo.toml index e402e0fb..05f98a1f 100644 --- a/starknet-macros/Cargo.toml +++ b/starknet-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-macros" -version = "0.2.0" +version = "0.2.1" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -16,7 +16,7 @@ keywords = ["ethereum", "starknet", "web3"] proc-macro = true [dependencies] -starknet-core = { version = "0.11.1", path = "../starknet-core" } +starknet-core = { version = "0.12.0", path = "../starknet-core" } syn = "2.0.15" [features] diff --git a/starknet-providers/Cargo.toml b/starknet-providers/Cargo.toml index 15055413..335a4fbf 100644 --- a/starknet-providers/Cargo.toml +++ b/starknet-providers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-providers" -version = "0.11.0" +version = "0.12.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -14,7 +14,7 @@ keywords = ["ethereum", "starknet", "web3"] exclude = ["test-data/**"] [dependencies] -starknet-core = { version = "0.11.1", path = "../starknet-core" } +starknet-core = { version = "0.12.0", path = "../starknet-core" } async-trait = "0.1.68" auto_impl = "1.0.1" ethereum-types = "0.14.1" diff --git a/starknet-signers/Cargo.toml b/starknet-signers/Cargo.toml index a51bb688..436c9d99 100644 --- a/starknet-signers/Cargo.toml +++ b/starknet-signers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-signers" -version = "0.9.0" +version = "0.10.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -13,8 +13,8 @@ Starknet signer implementations keywords = ["ethereum", "starknet", "web3"] [dependencies] -starknet-core = { version = "0.11.1", path = "../starknet-core" } -starknet-crypto = { version = "0.7.1", path = "../starknet-crypto" } +starknet-core = { version = "0.12.0", path = "../starknet-core" } +starknet-crypto = { version = "0.7.2", path = "../starknet-crypto" } async-trait = "0.1.68" auto_impl = "1.0.1" thiserror = "1.0.40" From 4a1273010e619dd6e284fe23d78426c1d60a61d0 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Thu, 19 Sep 2024 18:36:55 +0200 Subject: [PATCH 38/54] chore: bump `starknet-types-core` to `0.1.5` (#657) l --- Cargo.lock | 1004 ++++++++++++++++++------------------ starknet-core/Cargo.toml | 2 +- starknet-crypto/Cargo.toml | 4 +- starknet-curve/Cargo.toml | 2 +- 4 files changed, 501 insertions(+), 511 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c22a7bfa..7a9f29dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,30 +4,45 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aes" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", "cpufeatures", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -45,19 +60,19 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.77", ] [[package]] @@ -73,35 +88,34 @@ dependencies = [ [[package]] name = "auto_impl" -version = "1.0.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a8c1df849285fbacd587de7818cc7d13be6cd2cbcd47a04fb1801b0e2706e33" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.77", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -112,9 +126,9 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.21.0" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" @@ -151,9 +165,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvec" @@ -188,9 +202,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.1" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byte-slice-cast" @@ -206,9 +220,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cast" @@ -218,9 +232,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.99" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -230,22 +247,22 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ + "android-tzdata", "iana-time-zone", - "num-integer", "num-traits", "serde", - "winapi", + "windows-targets 0.52.6", ] [[package]] name = "ciborium" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -254,15 +271,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", @@ -280,9 +297,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.23" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "bitflags 1.3.2", "clap_lex", @@ -331,7 +348,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b3aeeec621f4daec552e9d28befd58020a78cfc364827d06a753e8bc13c6c4b" dependencies = [ - "base64 0.21.0", + "base64 0.21.7", "bech32", "bs58", "const-hex", @@ -396,26 +413,36 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -462,9 +489,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.5.1" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", "rand_core", @@ -493,9 +520,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.94" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" +checksum = "54ccead7d199d584d139148b04b4a368d1ec7556a1d9ea2548febb1b9d49f9a4" dependencies = [ "cc", "cxxbridge-flags", @@ -505,9 +532,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.94" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" +checksum = "c77953e99f01508f89f55c494bfa867171ef3a6c8cea03d26975368f2121a5c1" dependencies = [ "cc", "codespan-reporting", @@ -515,24 +542,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.63", + "syn 2.0.77", ] [[package]] name = "cxxbridge-flags" -version = "1.0.94" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" +checksum = "65777e06cc48f0cb0152024c77d6cf9e4bdb4408e7b48bea993d42fa0f5b02b6" [[package]] name = "cxxbridge-macro" -version = "1.0.94" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" +checksum = "98532a60dedaebc4848cb2cba5023337cc9ea3af16a5b062633fabfd9f18fb60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.77", ] [[package]] @@ -556,7 +583,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.63", + "syn 2.0.77", ] [[package]] @@ -567,7 +594,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.63", + "syn 2.0.77", ] [[package]] @@ -618,9 +645,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elliptic-curve" @@ -643,9 +670,9 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -729,12 +756,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.25" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", - "miniz_oxide 0.6.2", + "miniz_oxide", ] [[package]] @@ -745,9 +772,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -760,36 +787,36 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-task", @@ -810,9 +837,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -823,9 +850,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "group" @@ -840,9 +867,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.18" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -850,7 +877,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -859,9 +886,13 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] [[package]] name = "hashbrown" @@ -886,12 +917,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -928,9 +956,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -939,9 +967,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -950,21 +978,21 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", @@ -977,7 +1005,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2", "tokio", "tower-service", "tracing", @@ -986,10 +1014,11 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.2" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ + "futures-util", "http", "hyper", "rustls", @@ -999,26 +1028,25 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -1029,9 +1057,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1088,9 +1116,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -1108,9 +1136,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.7.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] name = "itertools" @@ -1123,15 +1151,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -1183,15 +1211,15 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libm" @@ -1213,18 +1241,18 @@ dependencies = [ [[package]] name = "link-cplusplus" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" dependencies = [ "cc", ] [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1232,15 +1260,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" @@ -1258,32 +1286,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] -name = "miniz_oxide" -version = "0.6.2" +name = "minicov" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" dependencies = [ - "adler", + "cc", + "walkdir", ] [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi 0.3.9", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1301,11 +1331,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -1318,11 +1347,10 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] @@ -1336,21 +1364,11 @@ dependencies = [ "libm", ] -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", -] - [[package]] name = "object" -version = "0.36.0" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] @@ -1363,21 +1381,21 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "os_str_bytes" -version = "6.5.0" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "parity-scale-codec" -version = "3.4.0" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec", "bitvec", @@ -1389,9 +1407,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.4" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1401,9 +1419,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1411,15 +1429,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.52.6", ] [[package]] @@ -1433,9 +1451,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" @@ -1473,15 +1491,18 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "primitive-types" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", @@ -1492,68 +1513,43 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.3.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "once_cell", "toml_edit", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "lazy_static", "num-traits", "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.4", + "regex-syntax", "unarray", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1605,27 +1601,35 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.8.1" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ - "regex-syntax 0.7.1", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "regex-syntax" -version = "0.7.1" +name = "regex-automata" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] [[package]] name = "regex-syntax" @@ -1635,11 +1639,11 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" -version = "0.11.16" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64 0.21.0", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -1661,6 +1665,8 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", + "system-configuration", "tokio", "tokio-rustls", "tower-service", @@ -1684,17 +1690,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.20" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", + "getrandom", "libc", - "once_cell", "spin", "untrusted", - "web-sys", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -1740,30 +1746,40 @@ checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" [[package]] name = "rustls" -version = "0.20.8" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", + "rustls-webpki", "sct", - "webpki", ] [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.0", + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", ] [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "salsa20" @@ -1791,15 +1807,15 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scratch" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" +checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" [[package]] name = "scrypt" @@ -1815,9 +1831,9 @@ dependencies = [ [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", @@ -1845,31 +1861,32 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -1907,7 +1924,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.6", + "indexmap 2.5.0", "serde", "serde_derive", "serde_json", @@ -1924,7 +1941,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.77", ] [[package]] @@ -1948,11 +1965,17 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -1969,28 +1992,18 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.9" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -2004,9 +2017,9 @@ dependencies = [ [[package]] name = "spin" -version = "0.5.2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spki" @@ -2072,7 +2085,7 @@ dependencies = [ name = "starknet-core" version = "0.12.0" dependencies = [ - "base64 0.21.0", + "base64 0.21.7", "bincode", "criterion", "crypto-bigint", @@ -2134,7 +2147,7 @@ name = "starknet-macros" version = "0.2.1" dependencies = [ "starknet-core", - "syn 2.0.63", + "syn 2.0.77", ] [[package]] @@ -2179,9 +2192,9 @@ dependencies = [ [[package]] name = "starknet-types-core" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe29a53d28ff630e4c7827788f14b28f9386d27cb9d05186a5f2e73218c34677" +checksum = "ce6bacf0ba19bc721e518bc4bf389ff13daa8a7c5db5fd320600473b8aa9fcbd" dependencies = [ "lambdaworks-crypto", "lambdaworks-math", @@ -2214,9 +2227,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.4.1" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2231,15 +2244,42 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.63" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -2248,37 +2288,37 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.77", ] [[package]] @@ -2333,9 +2373,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -2348,89 +2388,85 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.77", ] [[package]] name = "tokio-rustls" -version = "0.23.4" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", - "webpki", ] [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.22.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" dependencies = [ - "indexmap 1.9.3", + "indexmap 2.5.0", "toml_datetime", "winnow", ] [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2444,29 +2480,29 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.77", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "uint" @@ -2488,42 +2524,42 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.3.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -2548,15 +2584,15 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" -version = "2.3.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -2564,11 +2600,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -2580,34 +2615,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.77", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -2617,9 +2653,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2627,31 +2663,32 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-bindgen-test" -version = "0.3.34" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db36fc0f9fb209e88fb3642590ae0205bb5a56216dabd963ba15879fe53a30b" +checksum = "68497a05fb21143a08a7d24fc81763384a3072ee43c44e86aad1744d6adef9d9" dependencies = [ "console_error_panic_hook", "js-sys", + "minicov", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", @@ -2660,42 +2697,30 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.34" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0734759ae6b3b1717d661fe4f016efcfb9828f5edb4520c18eaee05af3b43be9" +checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" dependencies = [ "proc-macro2", "quote", + "syn 2.0.77", ] [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki-roots" -version = "0.22.6" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "winapi" @@ -2715,11 +2740,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -2729,21 +2754,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.42.2", + "windows-targets 0.52.6", ] [[package]] @@ -2752,7 +2768,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.5", ] [[package]] @@ -2761,203 +2777,156 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] -name = "windows-targets" -version = "0.42.2" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.52.6", ] [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.4.1" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] [[package]] @@ -2969,6 +2938,27 @@ dependencies = [ "tap", ] +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "zeroize" version = "1.8.1" diff --git a/starknet-core/Cargo.toml b/starknet-core/Cargo.toml index 41f74908..ba8c41b7 100644 --- a/starknet-core/Cargo.toml +++ b/starknet-core/Cargo.toml @@ -27,7 +27,7 @@ serde_json = { version = "1.0.96", default-features = false, features = ["alloc" serde_json_pythonic = { version = "0.1.2", default-features = false, features = ["alloc", "raw_value"] } serde_with = { version = "3.9.0", default-features = false, features = ["alloc", "macros"] } sha3 = { version = "0.10.7", default-features = false } -starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve", "serde", "num-traits"] } +starknet-types-core = { version = "0.1.5", default-features = false, features = ["curve", "serde", "num-traits"] } [dev-dependencies] bincode = "1.3.3" diff --git a/starknet-crypto/Cargo.toml b/starknet-crypto/Cargo.toml index 52c23b5b..9b159bcd 100644 --- a/starknet-crypto/Cargo.toml +++ b/starknet-crypto/Cargo.toml @@ -24,7 +24,7 @@ rfc6979 = { version = "0.4.0", default-features = false } sha2 = { version = "0.10.6", default-features = false } zeroize = { version = "1.6.0", default-features = false } hex = { version = "0.4.3", default-features = false, optional = true } -starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve", "hash"] } +starknet-types-core = { version = "0.1.5", default-features = false, features = ["curve", "hash"] } [features] default = ["std", "signature-display"] @@ -38,7 +38,7 @@ hex = "0.4.3" hex-literal = "0.4.1" serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0.96" -starknet-types-core = { version = "0.1.3", default-features = false, features = ["alloc"] } +starknet-types-core = { version = "0.1.5", default-features = false, features = ["alloc"] } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = "0.3.34" diff --git a/starknet-curve/Cargo.toml b/starknet-curve/Cargo.toml index ee2f084e..f003b259 100644 --- a/starknet-curve/Cargo.toml +++ b/starknet-curve/Cargo.toml @@ -13,7 +13,7 @@ Stark curve keywords = ["ethereum", "starknet", "web3", "no_std"] [dependencies] -starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve"] } +starknet-types-core = { version = "0.1.5", default-features = false, features = ["curve"] } [lints] workspace = true From 6853ac616bc886092440d8777c14cecd9ff53472 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Fri, 20 Sep 2024 06:45:53 +0200 Subject: [PATCH 39/54] chore: bump starknet-types-core to 0.1.6 (#658) --- Cargo.lock | 8 ++++---- starknet-core/Cargo.toml | 2 +- starknet-crypto/Cargo.toml | 4 ++-- starknet-curve/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a9f29dc..3922fa55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2192,9 +2192,9 @@ dependencies = [ [[package]] name = "starknet-types-core" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6bacf0ba19bc721e518bc4bf389ff13daa8a7c5db5fd320600473b8aa9fcbd" +checksum = "9b889ee5734db8b3c8a6551135c16764bf4ce1ab4955fffbb2ac5b6706542b64" dependencies = [ "lambdaworks-crypto", "lambdaworks-math", @@ -2545,9 +2545,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "untrusted" diff --git a/starknet-core/Cargo.toml b/starknet-core/Cargo.toml index ba8c41b7..f3302ac2 100644 --- a/starknet-core/Cargo.toml +++ b/starknet-core/Cargo.toml @@ -27,7 +27,7 @@ serde_json = { version = "1.0.96", default-features = false, features = ["alloc" serde_json_pythonic = { version = "0.1.2", default-features = false, features = ["alloc", "raw_value"] } serde_with = { version = "3.9.0", default-features = false, features = ["alloc", "macros"] } sha3 = { version = "0.10.7", default-features = false } -starknet-types-core = { version = "0.1.5", default-features = false, features = ["curve", "serde", "num-traits"] } +starknet-types-core = { version = "0.1.6", default-features = false, features = ["curve", "serde", "num-traits"] } [dev-dependencies] bincode = "1.3.3" diff --git a/starknet-crypto/Cargo.toml b/starknet-crypto/Cargo.toml index 9b159bcd..b0989925 100644 --- a/starknet-crypto/Cargo.toml +++ b/starknet-crypto/Cargo.toml @@ -24,7 +24,7 @@ rfc6979 = { version = "0.4.0", default-features = false } sha2 = { version = "0.10.6", default-features = false } zeroize = { version = "1.6.0", default-features = false } hex = { version = "0.4.3", default-features = false, optional = true } -starknet-types-core = { version = "0.1.5", default-features = false, features = ["curve", "hash"] } +starknet-types-core = { version = "0.1.6", default-features = false, features = ["curve", "hash"] } [features] default = ["std", "signature-display"] @@ -38,7 +38,7 @@ hex = "0.4.3" hex-literal = "0.4.1" serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0.96" -starknet-types-core = { version = "0.1.5", default-features = false, features = ["alloc"] } +starknet-types-core = { version = "0.1.6", default-features = false, features = ["alloc"] } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = "0.3.34" diff --git a/starknet-curve/Cargo.toml b/starknet-curve/Cargo.toml index f003b259..0f3da9a6 100644 --- a/starknet-curve/Cargo.toml +++ b/starknet-curve/Cargo.toml @@ -13,7 +13,7 @@ Stark curve keywords = ["ethereum", "starknet", "web3", "no_std"] [dependencies] -starknet-types-core = { version = "0.1.5", default-features = false, features = ["curve"] } +starknet-types-core = { version = "0.1.6", default-features = false, features = ["curve"] } [lints] workspace = true From 1111a72ba53eb1ad5f1270cd9488162a1aec0916 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 30 Sep 2024 01:46:44 +0800 Subject: [PATCH 40/54] chore: make nightly clippy happy again (#662) Allows `clippy::needless_return` as it causes false positives in tests. --- .github/workflows/lint.yaml | 2 +- starknet-accounts/src/account/declaration.rs | 4 ++-- starknet-accounts/src/account/execution.rs | 4 ++-- starknet-accounts/src/factory/mod.rs | 4 ++-- starknet-accounts/tests/single_owner_account.rs | 4 ++-- starknet-contract/tests/contract_deployment.rs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 43bb0dab..e96896c7 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -81,7 +81,7 @@ jobs: - name: "Set allowed lints" run: | if [ "${{ matrix.toolchain }}" == "nightly" ]; then - echo "ALLOWED=-A non_local_definitions -A clippy::too_long_first_doc_paragraph" >> $GITHUB_ENV + echo "ALLOWED=-A non_local_definitions -A clippy::too_long_first_doc_paragraph -A clippy::needless_return" >> $GITHUB_ENV else echo "ALLOWED=" >> $GITHUB_ENV fi diff --git a/starknet-accounts/src/account/declaration.rs b/starknet-accounts/src/account/declaration.rs index cca83010..0f07b5f8 100644 --- a/starknet-accounts/src/account/declaration.rs +++ b/starknet-accounts/src/account/declaration.rs @@ -486,8 +486,8 @@ where let gas_price = u64::from_le_bytes(gas_price_bytes[..8].try_into().unwrap()); - (((overall_fee + gas_price - 1) / gas_price) as f64 - * self.gas_estimate_multiplier) as u64 + (overall_fee.div_ceil(gas_price) as f64 * self.gas_estimate_multiplier) + as u64 } }; diff --git a/starknet-accounts/src/account/execution.rs b/starknet-accounts/src/account/execution.rs index c3f75f38..b94040ba 100644 --- a/starknet-accounts/src/account/execution.rs +++ b/starknet-accounts/src/account/execution.rs @@ -466,8 +466,8 @@ where let gas_price = u64::from_le_bytes(gas_price_bytes[..8].try_into().unwrap()); - ((((overall_fee + gas_price - 1) / gas_price) as f64) - * self.gas_estimate_multiplier) as u64 + ((overall_fee.div_ceil(gas_price) as f64) * self.gas_estimate_multiplier) + as u64 } }; diff --git a/starknet-accounts/src/factory/mod.rs b/starknet-accounts/src/factory/mod.rs index c72ab017..b893abc3 100644 --- a/starknet-accounts/src/factory/mod.rs +++ b/starknet-accounts/src/factory/mod.rs @@ -694,8 +694,8 @@ where let gas_price = u64::from_le_bytes(gas_price_bytes[..8].try_into().unwrap()); - ((((overall_fee + gas_price - 1) / gas_price) as f64) - * self.gas_estimate_multiplier) as u64 + ((overall_fee.div_ceil(gas_price) as f64) * self.gas_estimate_multiplier) + as u64 } }; diff --git a/starknet-accounts/tests/single_owner_account.rs b/starknet-accounts/tests/single_owner_account.rs index 808093f4..8b1eb038 100644 --- a/starknet-accounts/tests/single_owner_account.rs +++ b/starknet-accounts/tests/single_owner_account.rs @@ -355,7 +355,7 @@ async fn can_execute_eth_transfer_invoke_v3_inner( calldata: vec![Felt::from_hex("0x1234").unwrap(), Felt::ONE, Felt::ZERO], }]) .gas(100000) - .gas_price(800000000000000) + .gas_price(900000000000000) .send() .await .unwrap(); @@ -545,7 +545,7 @@ async fn can_declare_cairo1_contract_v3_inner( Felt::from_hex(&hashes.compiled_class_hash).unwrap(), ) .gas(100000) - .gas_price(800000000000000) + .gas_price(900000000000000) .send() .await .unwrap(); diff --git a/starknet-contract/tests/contract_deployment.rs b/starknet-contract/tests/contract_deployment.rs index 5720d100..d656776b 100644 --- a/starknet-contract/tests/contract_deployment.rs +++ b/starknet-contract/tests/contract_deployment.rs @@ -81,7 +81,7 @@ async fn can_deploy_contract_to_alpha_sepolia_with_invoke_v3() { let result = factory .deploy_v3(vec![Felt::ONE], Felt::from_bytes_be(&salt_buffer), true) .gas(100000) - .gas_price(800000000000000) + .gas_price(900000000000000) .send() .await; From e73a71df8270e5cdd9d50d96ddd4ad2749b709ef Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 30 Sep 2024 01:54:46 +0800 Subject: [PATCH 41/54] chore: adapt wasmtime 14 CLI parsing changes (#661) --- scripts/run_bench_wasm.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/run_bench_wasm.sh b/scripts/run_bench_wasm.sh index a36ae83f..008b6175 100755 --- a/scripts/run_bench_wasm.sh +++ b/scripts/run_bench_wasm.sh @@ -27,5 +27,10 @@ benches=( ) for bench in ${benches[@]}; do - $RUNTIME run --dir=. $REPO_ROOT/target/bench-wasm/$bench.wasm -- --bench + if [[ "$RUNTIME" == "wasmtime" ]]; then + # https://github.com/bytecodealliance/wasmtime/issues/7384 + $RUNTIME run --dir=. -- $REPO_ROOT/target/bench-wasm/$bench.wasm --bench + else + $RUNTIME run --dir=. $REPO_ROOT/target/bench-wasm/$bench.wasm -- --bench + fi done From 1b1071e2c5975c8810c1b05b776aaa58cb172037 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 30 Sep 2024 02:02:50 +0800 Subject: [PATCH 42/54] ci: run tests on Apple silicon runners (#663) --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2ba9b375..b3b9c8a6 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-12] + os: [ubuntu-latest, macos-13, macos-14] toolchain: [stable, nightly] steps: From 8f79beaa41660f90fede10269b91221e8b120fd1 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 21 Oct 2024 03:24:51 +0800 Subject: [PATCH 43/54] chore: make nightly clippy happy again (#668) --- starknet-accounts/src/account/declaration.rs | 6 +-- starknet-accounts/src/account/execution.rs | 4 +- starknet-contract/src/factory.rs | 8 +-- starknet-core/src/serde/byte_array.rs | 2 +- starknet-core/src/serde/num_hex.rs | 2 +- .../src/serde/unsigned_field_element.rs | 6 +-- starknet-core/src/types/codegen.rs | 50 +++++++++---------- starknet-core/src/types/eth_address.rs | 2 +- starknet-core/src/types/hash_256.rs | 2 +- starknet-core/src/types/serde_impls.rs | 4 +- .../src/sequencer/models/serde_impls.rs | 6 +-- .../src/sequencer/models/transaction.rs | 2 +- 12 files changed, 47 insertions(+), 47 deletions(-) diff --git a/starknet-accounts/src/account/declaration.rs b/starknet-accounts/src/account/declaration.rs index 0f07b5f8..4fff8855 100644 --- a/starknet-accounts/src/account/declaration.rs +++ b/starknet-accounts/src/account/declaration.rs @@ -1007,7 +1007,7 @@ impl RawLegacyDeclaration { } } -impl<'a, A> PreparedDeclarationV2<'a, A> +impl PreparedDeclarationV2<'_, A> where A: Account, { @@ -1057,7 +1057,7 @@ where } } -impl<'a, A> PreparedDeclarationV3<'a, A> +impl PreparedDeclarationV3<'_, A> where A: Account, { @@ -1126,7 +1126,7 @@ where } } -impl<'a, A> PreparedLegacyDeclaration<'a, A> +impl PreparedLegacyDeclaration<'_, A> where A: Account, { diff --git a/starknet-accounts/src/account/execution.rs b/starknet-accounts/src/account/execution.rs index b94040ba..00aa956b 100644 --- a/starknet-accounts/src/account/execution.rs +++ b/starknet-accounts/src/account/execution.rs @@ -730,7 +730,7 @@ impl RawExecutionV3 { } } -impl<'a, A> PreparedExecutionV1<'a, A> +impl PreparedExecutionV1<'_, A> where A: Account, { @@ -746,7 +746,7 @@ where } } -impl<'a, A> PreparedExecutionV3<'a, A> +impl PreparedExecutionV3<'_, A> where A: Account, { diff --git a/starknet-contract/src/factory.rs b/starknet-contract/src/factory.rs index 65416722..cc93aa01 100644 --- a/starknet-contract/src/factory.rs +++ b/starknet-contract/src/factory.rs @@ -139,7 +139,7 @@ where } } -impl<'f, A> DeploymentV1<'f, A> { +impl DeploymentV1<'_, A> { /// Returns a new [`DeploymentV1`] with the `nonce`. pub fn nonce(self, nonce: Felt) -> Self { Self { @@ -167,7 +167,7 @@ impl<'f, A> DeploymentV1<'f, A> { } } -impl<'f, A> DeploymentV3<'f, A> { +impl DeploymentV3<'_, A> { /// Returns a new [`DeploymentV3`] with the `nonce`. pub fn nonce(self, nonce: Felt) -> Self { Self { @@ -213,7 +213,7 @@ impl<'f, A> DeploymentV3<'f, A> { } } -impl<'f, A> DeploymentV1<'f, A> +impl DeploymentV1<'_, A> where A: Account, { @@ -235,7 +235,7 @@ where } } -impl<'f, A> DeploymentV3<'f, A> +impl DeploymentV3<'_, A> where A: Account, { diff --git a/starknet-core/src/serde/byte_array.rs b/starknet-core/src/serde/byte_array.rs index 70b6ed6e..3fa0fb64 100644 --- a/starknet-core/src/serde/byte_array.rs +++ b/starknet-core/src/serde/byte_array.rs @@ -24,7 +24,7 @@ pub mod base64 { deserializer.deserialize_any(Base64Visitor) } - impl<'de> Visitor<'de> for Base64Visitor { + impl Visitor<'_> for Base64Visitor { type Value = Vec; fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { diff --git a/starknet-core/src/serde/num_hex.rs b/starknet-core/src/serde/num_hex.rs index f285a18a..2026be40 100644 --- a/starknet-core/src/serde/num_hex.rs +++ b/starknet-core/src/serde/num_hex.rs @@ -27,7 +27,7 @@ pub mod u64 { } } - impl<'de> Visitor<'de> for NumHexVisitor { + impl Visitor<'_> for NumHexVisitor { type Value = u64; fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { diff --git a/starknet-core/src/serde/unsigned_field_element.rs b/starknet-core/src/serde/unsigned_field_element.rs index f42606a8..380b68a2 100644 --- a/starknet-core/src/serde/unsigned_field_element.rs +++ b/starknet-core/src/serde/unsigned_field_element.rs @@ -55,7 +55,7 @@ impl<'de> DeserializeAs<'de, Felt> for UfeHex { } } -impl<'de> Visitor<'de> for UfeHexVisitor { +impl Visitor<'_> for UfeHexVisitor { type Value = Felt; fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { @@ -112,7 +112,7 @@ impl<'de> DeserializeAs<'de, Option> for UfeHexOption { } } -impl<'de> Visitor<'de> for UfeHexOptionVisitor { +impl Visitor<'_> for UfeHexOptionVisitor { type Value = Option; fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { @@ -180,7 +180,7 @@ impl<'de> DeserializeAs<'de, Option> for UfePendingBlockHash { } } -impl<'de> Visitor<'de> for UfePendingBlockHashVisitor { +impl Visitor<'_> for UfePendingBlockHashVisitor { type Value = Option; fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { diff --git a/starknet-core/src/types/codegen.rs b/starknet-core/src/types/codegen.rs index a4483a37..e4890f3f 100644 --- a/starknet-core/src/types/codegen.rs +++ b/starknet-core/src/types/codegen.rs @@ -3,7 +3,7 @@ // https://github.com/xJonathanLEI/starknet-jsonrpc-codegen // Code generated with version: -// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen#f1278dfb2ae57d319093421c038f6ec7a3dfba2f +// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen#66aa909a760ed0800232a2ca13ece97b9ea32d24 // These types are ignored from code generation. Implement them manually: // - `RECEIPT_BLOCK` @@ -4595,7 +4595,7 @@ impl Serialize for AddDeclareTransactionRequest { } } -impl<'a> Serialize for AddDeclareTransactionRequestRef<'a> { +impl Serialize for AddDeclareTransactionRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -4672,7 +4672,7 @@ impl Serialize for AddDeployAccountTransactionRequest { } } -impl<'a> Serialize for AddDeployAccountTransactionRequestRef<'a> { +impl Serialize for AddDeployAccountTransactionRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -4749,7 +4749,7 @@ impl Serialize for AddInvokeTransactionRequest { } } -impl<'a> Serialize for AddInvokeTransactionRequestRef<'a> { +impl Serialize for AddInvokeTransactionRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -4873,7 +4873,7 @@ impl Serialize for CallRequest { } } -impl<'a> Serialize for CallRequestRef<'a> { +impl Serialize for CallRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -5011,7 +5011,7 @@ impl Serialize for EstimateFeeRequest { } } -impl<'a> Serialize for EstimateFeeRequestRef<'a> { +impl Serialize for EstimateFeeRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -5145,7 +5145,7 @@ impl Serialize for EstimateMessageFeeRequest { } } -impl<'a> Serialize for EstimateMessageFeeRequestRef<'a> { +impl Serialize for EstimateMessageFeeRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -5246,7 +5246,7 @@ impl Serialize for GetBlockTransactionCountRequest { } } -impl<'a> Serialize for GetBlockTransactionCountRequestRef<'a> { +impl Serialize for GetBlockTransactionCountRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -5323,7 +5323,7 @@ impl Serialize for GetBlockWithReceiptsRequest { } } -impl<'a> Serialize for GetBlockWithReceiptsRequestRef<'a> { +impl Serialize for GetBlockWithReceiptsRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -5400,7 +5400,7 @@ impl Serialize for GetBlockWithTxHashesRequest { } } -impl<'a> Serialize for GetBlockWithTxHashesRequestRef<'a> { +impl Serialize for GetBlockWithTxHashesRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -5477,7 +5477,7 @@ impl Serialize for GetBlockWithTxsRequest { } } -impl<'a> Serialize for GetBlockWithTxsRequestRef<'a> { +impl Serialize for GetBlockWithTxsRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -5565,7 +5565,7 @@ impl Serialize for GetClassAtRequest { } } -impl<'a> Serialize for GetClassAtRequestRef<'a> { +impl Serialize for GetClassAtRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -5682,7 +5682,7 @@ impl Serialize for GetClassHashAtRequest { } } -impl<'a> Serialize for GetClassHashAtRequestRef<'a> { +impl Serialize for GetClassHashAtRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -5799,7 +5799,7 @@ impl Serialize for GetClassRequest { } } -impl<'a> Serialize for GetClassRequestRef<'a> { +impl Serialize for GetClassRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -5905,7 +5905,7 @@ impl Serialize for GetEventsRequest { } } -impl<'a> Serialize for GetEventsRequestRef<'a> { +impl Serialize for GetEventsRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -5993,7 +5993,7 @@ impl Serialize for GetNonceRequest { } } -impl<'a> Serialize for GetNonceRequestRef<'a> { +impl Serialize for GetNonceRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -6099,7 +6099,7 @@ impl Serialize for GetStateUpdateRequest { } } -impl<'a> Serialize for GetStateUpdateRequestRef<'a> { +impl Serialize for GetStateUpdateRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -6196,7 +6196,7 @@ impl Serialize for GetStorageAtRequest { } } -impl<'a> Serialize for GetStorageAtRequestRef<'a> { +impl Serialize for GetStorageAtRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[serde_as] #[derive(Serialize)] @@ -6336,7 +6336,7 @@ impl Serialize for GetTransactionByBlockIdAndIndexRequest { } } -impl<'a> Serialize for GetTransactionByBlockIdAndIndexRequestRef<'a> { +impl Serialize for GetTransactionByBlockIdAndIndexRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -6437,7 +6437,7 @@ impl Serialize for GetTransactionByHashRequest { } } -impl<'a> Serialize for GetTransactionByHashRequestRef<'a> { +impl Serialize for GetTransactionByHashRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[serde_as] #[derive(Serialize)] @@ -6521,7 +6521,7 @@ impl Serialize for GetTransactionReceiptRequest { } } -impl<'a> Serialize for GetTransactionReceiptRequestRef<'a> { +impl Serialize for GetTransactionReceiptRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[serde_as] #[derive(Serialize)] @@ -6605,7 +6605,7 @@ impl Serialize for GetTransactionStatusRequest { } } -impl<'a> Serialize for GetTransactionStatusRequestRef<'a> { +impl Serialize for GetTransactionStatusRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[serde_as] #[derive(Serialize)] @@ -6705,7 +6705,7 @@ impl Serialize for SimulateTransactionsRequest { } } -impl<'a> Serialize for SimulateTransactionsRequestRef<'a> { +impl Serialize for SimulateTransactionsRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -6868,7 +6868,7 @@ impl Serialize for TraceBlockTransactionsRequest { } } -impl<'a> Serialize for TraceBlockTransactionsRequestRef<'a> { +impl Serialize for TraceBlockTransactionsRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[derive(Serialize)] #[serde(transparent)] @@ -6947,7 +6947,7 @@ impl Serialize for TraceTransactionRequest { } } -impl<'a> Serialize for TraceTransactionRequestRef<'a> { +impl Serialize for TraceTransactionRequestRef<'_> { fn serialize(&self, serializer: S) -> Result { #[serde_as] #[derive(Serialize)] diff --git a/starknet-core/src/types/eth_address.rs b/starknet-core/src/types/eth_address.rs index bfe2924d..1d0409ae 100644 --- a/starknet-core/src/types/eth_address.rs +++ b/starknet-core/src/types/eth_address.rs @@ -117,7 +117,7 @@ impl<'de> Deserialize<'de> for EthAddress { } } -impl<'de> Visitor<'de> for EthAddressVisitor { +impl Visitor<'_> for EthAddressVisitor { type Value = EthAddress; fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { diff --git a/starknet-core/src/types/hash_256.rs b/starknet-core/src/types/hash_256.rs index 475e9b41..4513d8f6 100644 --- a/starknet-core/src/types/hash_256.rs +++ b/starknet-core/src/types/hash_256.rs @@ -108,7 +108,7 @@ impl<'de> Deserialize<'de> for Hash256 { } } -impl<'de> Visitor<'de> for Hash256Visitor { +impl Visitor<'_> for Hash256Visitor { type Value = Hash256; fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { diff --git a/starknet-core/src/types/serde_impls.rs b/starknet-core/src/types/serde_impls.rs index 925321c8..fc65b64b 100644 --- a/starknet-core/src/types/serde_impls.rs +++ b/starknet-core/src/types/serde_impls.rs @@ -55,7 +55,7 @@ impl<'de> DeserializeAs<'de, u128> for NumAsHex { } } -impl<'de> Visitor<'de> for NumAsHexVisitorU64 { +impl Visitor<'_> for NumAsHexVisitorU64 { type Value = u64; fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { @@ -95,7 +95,7 @@ impl<'de> Visitor<'de> for NumAsHexVisitorU64 { } } -impl<'de> Visitor<'de> for NumAsHexVisitorU128 { +impl Visitor<'_> for NumAsHexVisitorU128 { type Value = u128; fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { diff --git a/starknet-providers/src/sequencer/models/serde_impls.rs b/starknet-providers/src/sequencer/models/serde_impls.rs index fda5b8e7..92eaae14 100644 --- a/starknet-providers/src/sequencer/models/serde_impls.rs +++ b/starknet-providers/src/sequencer/models/serde_impls.rs @@ -17,7 +17,7 @@ pub(crate) mod u64_hex { deserializer.deserialize_any(U64HexVisitor) } - impl<'de> Visitor<'de> for U64HexVisitor { + impl Visitor<'_> for U64HexVisitor { type Value = u64; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -53,7 +53,7 @@ pub(crate) mod u128_hex { deserializer.deserialize_any(U128HexVisitor) } - impl<'de> Visitor<'de> for U128HexVisitor { + impl Visitor<'_> for U128HexVisitor { type Value = u128; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -92,7 +92,7 @@ pub(crate) mod u64_hex_opt { deserializer.deserialize_any(U64HexOptVisitor) } - impl<'de> Visitor<'de> for U64HexOptVisitor { + impl Visitor<'_> for U64HexOptVisitor { type Value = Option; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/starknet-providers/src/sequencer/models/transaction.rs b/starknet-providers/src/sequencer/models/transaction.rs index 75aaa0b6..da14f044 100644 --- a/starknet-providers/src/sequencer/models/transaction.rs +++ b/starknet-providers/src/sequencer/models/transaction.rs @@ -278,7 +278,7 @@ impl<'de> Deserialize<'de> for DataAvailabilityMode { } } -impl<'de> Visitor<'de> for DataAvailabilityModeVisitor { +impl Visitor<'_> for DataAvailabilityModeVisitor { type Value = DataAvailabilityMode; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { From 1fc8b91efd861542ad69b2e3d4b1c38bc350c7de Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 21 Oct 2024 11:38:16 +0800 Subject: [PATCH 44/54] feat: serialization to and from felts (#669) --- Cargo.lock | 16 +- Cargo.toml | 2 + README.md | 19 +- assets/CORE_DERIVE_README.md | 1 + examples/serde.rs | 34 ++ starknet-core-derive/Cargo.toml | 28 ++ starknet-core-derive/README.md | 14 + starknet-core-derive/src/lib.rs | 373 ++++++++++++++++ starknet-core/Cargo.toml | 2 + starknet-core/src/codec.rs | 747 ++++++++++++++++++++++++++++++++ starknet-core/src/lib.rs | 3 + 11 files changed, 1229 insertions(+), 10 deletions(-) create mode 120000 assets/CORE_DERIVE_README.md create mode 100644 examples/serde.rs create mode 100644 starknet-core-derive/Cargo.toml create mode 100644 starknet-core-derive/README.md create mode 100644 starknet-core-derive/src/lib.rs create mode 100644 starknet-core/src/codec.rs diff --git a/Cargo.lock b/Cargo.lock index 3922fa55..21652b6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1522,9 +1522,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] @@ -2039,6 +2039,7 @@ dependencies = [ "starknet-accounts", "starknet-contract", "starknet-core", + "starknet-core-derive", "starknet-crypto", "starknet-macros", "starknet-providers", @@ -2092,17 +2093,28 @@ dependencies = [ "flate2", "hex", "hex-literal", + "num-traits", "serde", "serde_json", "serde_json_pythonic", "serde_with", "sha3", "starknet-core", + "starknet-core-derive", "starknet-crypto", "starknet-types-core", "wasm-bindgen-test", ] +[[package]] +name = "starknet-core-derive" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "starknet-crypto" version = "0.7.2" diff --git a/Cargo.toml b/Cargo.toml index 831cc42a..3e2ad949 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ exclude = [".github/**", "images/**"] [workspace] members = [ "starknet-core", + "starknet-core-derive", "starknet-providers", "starknet-contract", "starknet-crypto", @@ -34,6 +35,7 @@ all-features = true [dependencies] starknet-crypto = { version = "0.7.2", path = "./starknet-crypto" } starknet-core = { version = "0.12.0", path = "./starknet-core", default-features = false } +starknet-core-derive = { version = "0.1.0", path = "./starknet-core-derive", features = ["import_from_starknet"] } starknet-providers = { version = "0.12.0", path = "./starknet-providers" } starknet-contract = { version = "0.11.0", path = "./starknet-contract" } starknet-signers = { version = "0.10.0", path = "./starknet-signers" } diff --git a/README.md b/README.md index 3371af44..c6d4e2a8 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ This workspace contains the following crates: - `starknet-accounts`: Types for handling Starknet account abstraction - `starknet-curve`: Starknet curve operations - `starknet-macros`: Useful macros for using the `starknet` crates +- `starknet-core-derive`: Derive macros for traits in `starknet-core` ## WebAssembly @@ -92,21 +93,23 @@ Examples can be found in the [examples folder](./examples): 6. [Query the latest block number with JSON-RPC](./examples/jsonrpc.rs) -7. [Batched JSON-RPC requests](./examples/batch.rs) +7. [Encoding and decoding Cairo types](./examples/serde.rs) -8. [Call a contract view function](./examples/erc20_balance.rs) +8. [Batched JSON-RPC requests](./examples/batch.rs) -9. [Deploy an Argent X account to a pre-funded address](./examples/deploy_argent_account.rs) +9. [Call a contract view function](./examples/erc20_balance.rs) -10. [Inspect public key with Ledger](./examples/ledger_public_key.rs) +10. [Deploy an Argent X account to a pre-funded address](./examples/deploy_argent_account.rs) -11. [Deploy an OpenZeppelin account with Ledger](./examples/deploy_account_with_ledger.rs) +11. [Inspect public key with Ledger](./examples/ledger_public_key.rs) -12. [Transfer ERC20 tokens with Ledger](./examples/transfer_with_ledger.rs) +12. [Deploy an OpenZeppelin account with Ledger](./examples/deploy_account_with_ledger.rs) -13. [Parsing a JSON-RPC request on the server side](./examples/parse_jsonrpc_request.rs) +13. [Transfer ERC20 tokens with Ledger](./examples/transfer_with_ledger.rs) -14. [Inspecting a erased provider-specific error type](./examples/downcast_provider_error.rs) +14. [Parsing a JSON-RPC request on the server side](./examples/parse_jsonrpc_request.rs) + +15. [Inspecting a erased provider-specific error type](./examples/downcast_provider_error.rs) ## License diff --git a/assets/CORE_DERIVE_README.md b/assets/CORE_DERIVE_README.md new file mode 120000 index 00000000..430edd5f --- /dev/null +++ b/assets/CORE_DERIVE_README.md @@ -0,0 +1 @@ +../starknet-core-derive/README.md \ No newline at end of file diff --git a/examples/serde.rs b/examples/serde.rs new file mode 100644 index 00000000..4c80d530 --- /dev/null +++ b/examples/serde.rs @@ -0,0 +1,34 @@ +use starknet::{ + core::{ + codec::{Decode, Encode}, + types::Felt, + }, + macros::felt, +}; + +#[derive(Debug, Eq, PartialEq, Encode, Decode)] +struct CairoType { + a: Felt, + b: Option, + c: bool, +} + +fn main() { + let instance = CairoType { + a: felt!("123456789"), + b: Some(100), + c: false, + }; + + let mut serialized = vec![]; + instance.encode(&mut serialized).unwrap(); + + assert_eq!( + serialized, + [felt!("123456789"), felt!("0"), felt!("100"), felt!("0")] + ); + + let restored = CairoType::decode(&serialized).unwrap(); + + assert_eq!(instance, restored); +} diff --git a/starknet-core-derive/Cargo.toml b/starknet-core-derive/Cargo.toml new file mode 100644 index 00000000..bcc687fa --- /dev/null +++ b/starknet-core-derive/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "starknet-core-derive" +version = "0.1.0" +authors = ["Jonathan LEI "] +license = "MIT OR Apache-2.0" +edition = "2021" +readme = "README.md" +repository = "https://github.com/xJonathanLEI/starknet-rs" +homepage = "https://starknet.rs/" +description = """ +Procedural macros for `starknet-core` +""" +keywords = ["ethereum", "starknet", "web3"] + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.88" +quote = "1.0.37" +syn = "2.0.15" + +[features] +default = [] +import_from_starknet = [] + +[lints] +workspace = true diff --git a/starknet-core-derive/README.md b/starknet-core-derive/README.md new file mode 100644 index 00000000..42911dd7 --- /dev/null +++ b/starknet-core-derive/README.md @@ -0,0 +1,14 @@ +# Procedural macros for `starknet-core` + +This crate provides procedural macros for deriving the `Encode` and `Decode` traits from `starknet-core`. This allows defining a type like: + +```rust +#[derive(Debug, PartialEq, Eq, Decode, Encode)] +struct CairoType { + a: Felt, + b: U256, + c: bool, +} +``` + +and using the `::encode()` and `::decode()` methods, without manually implementing the corresponding traits. diff --git a/starknet-core-derive/src/lib.rs b/starknet-core-derive/src/lib.rs new file mode 100644 index 00000000..b7aadf85 --- /dev/null +++ b/starknet-core-derive/src/lib.rs @@ -0,0 +1,373 @@ +//! Procedural derive macros for the `starknet-core` crate. + +#![deny(missing_docs)] + +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::quote; +use syn::{ + parse::{Error as ParseError, Parse, ParseStream}, + parse_macro_input, DeriveInput, Fields, LitInt, LitStr, Meta, Token, +}; + +#[derive(Default)] +struct Args { + core: Option, +} + +impl Args { + fn merge(&mut self, other: Self) { + if let Some(core) = other.core { + if self.core.is_some() { + panic!("starknet attribute `core` defined more than once"); + } else { + self.core = Some(core); + } + } + } +} + +impl Parse for Args { + fn parse(input: ParseStream<'_>) -> Result { + let mut core: Option = None; + + while !input.is_empty() { + let lookahead = input.lookahead1(); + if lookahead.peek(kw::core) { + let _ = input.parse::()?; + let _ = input.parse::()?; + let value = input.parse::()?; + + match core { + Some(_) => { + return Err(ParseError::new( + Span::call_site(), + "starknet attribute `core` defined more than once", + )) + } + None => { + core = Some(value); + } + } + } else { + return Err(lookahead.error()); + } + } + + Ok(Self { core }) + } +} + +mod kw { + syn::custom_keyword!(core); +} + +/// Derives the `Encode` trait. +#[proc_macro_derive(Encode, attributes(starknet))] +pub fn derive_encode(input: TokenStream) -> TokenStream { + let input: DeriveInput = parse_macro_input!(input); + let ident = &input.ident; + + let core = derive_core_path(&input); + + let impl_block = match input.data { + syn::Data::Struct(data) => { + let field_impls = data.fields.iter().enumerate().map(|(ind_field, field)| { + let field_ident = match &field.ident { + Some(field_ident) => quote! { self.#field_ident }, + None => { + let ind_field = syn::Index::from(ind_field); + quote! { self.#ind_field } + } + }; + let field_type = &field.ty; + + quote! { + <#field_type as #core::codec::Encode>::encode(&#field_ident, writer)?; + } + }); + + quote! { + #(#field_impls)* + } + } + syn::Data::Enum(data) => { + let variant_impls = + data.variants + .iter() + .enumerate() + .map(|(ind_variant, variant)| { + let variant_ident = &variant.ident; + let ind_variant = int_to_felt(ind_variant, &core); + + match &variant.fields { + Fields::Named(fields_named) => { + let names = fields_named + .named + .iter() + .map(|field| field.ident.as_ref().unwrap()); + + let field_impls = fields_named.named.iter().map(|field| { + let field_ident = field.ident.as_ref().unwrap(); + let field_type = &field.ty; + + quote! { + <#field_type as #core::codec::Encode> + ::encode(#field_ident, writer)?; + } + }); + + quote! { + Self::#variant_ident { #(#names),* } => { + writer.write(#ind_variant); + #(#field_impls)* + }, + } + } + Fields::Unnamed(fields_unnamed) => { + let names = fields_unnamed.unnamed.iter().enumerate().map( + |(ind_field, _)| { + syn::Ident::new( + &format!("field_{}", ind_field), + Span::call_site(), + ) + }, + ); + + let field_impls = fields_unnamed.unnamed.iter().enumerate().map( + |(ind_field, field)| { + let field_ident = syn::Ident::new( + &format!("field_{}", ind_field), + Span::call_site(), + ); + let field_type = &field.ty; + + quote! { + <#field_type as #core::codec::Encode> + ::encode(#field_ident, writer)?; + } + }, + ); + + quote! { + Self::#variant_ident( #(#names),* ) => { + writer.write(#ind_variant); + #(#field_impls)* + }, + } + } + Fields::Unit => { + quote! { + Self::#variant_ident => { + writer.write(#ind_variant); + }, + } + } + } + }); + + quote! { + match self { + #(#variant_impls)* + } + } + } + syn::Data::Union(_) => panic!("union type not supported"), + }; + + quote! { + #[automatically_derived] + impl #core::codec::Encode for #ident { + fn encode(&self, writer: &mut W) + -> ::core::result::Result<(), #core::codec::Error> { + #impl_block + + Ok(()) + } + } + } + .into() +} + +/// Derives the `Decode` trait. +#[proc_macro_derive(Decode, attributes(starknet))] +pub fn derive_decode(input: TokenStream) -> TokenStream { + let input: DeriveInput = parse_macro_input!(input); + let ident = &input.ident; + + let core = derive_core_path(&input); + + let impl_block = match input.data { + syn::Data::Struct(data) => match &data.fields { + Fields::Named(fields_named) => { + let field_impls = fields_named.named.iter().map(|field| { + let field_ident = &field.ident; + let field_type = &field.ty; + + quote! { + #field_ident: <#field_type as #core::codec::Decode> + ::decode_iter(iter)?, + } + }); + + quote! { + Ok(Self { + #(#field_impls)* + }) + } + } + Fields::Unnamed(fields_unnamed) => { + let field_impls = fields_unnamed.unnamed.iter().map(|field| { + let field_type = &field.ty; + quote! { + <#field_type as #core::codec::Decode>::decode_iter(iter)? + } + }); + + quote! { + Ok(Self ( + #(#field_impls),* + )) + } + } + Fields::Unit => { + quote! { + Ok(Self) + } + } + }, + syn::Data::Enum(data) => { + let variant_impls = data + .variants + .iter() + .enumerate() + .map(|(ind_variant, variant)| { + let variant_ident = &variant.ident; + let ind_variant = int_to_felt(ind_variant, &core); + + let decode_impl = match &variant.fields { + Fields::Named(fields_named) => { + let field_impls = fields_named.named.iter().map(|field| { + let field_ident = field.ident.as_ref().unwrap(); + let field_type = &field.ty; + + quote! { + #field_ident: <#field_type as #core::codec::Decode> + ::decode_iter(iter)?, + } + }); + + quote! { + return Ok(Self::#variant_ident { + #(#field_impls)* + }); + } + } + Fields::Unnamed(fields_unnamed) => { + let field_impls = fields_unnamed.unnamed.iter().map(|field| { + let field_type = &field.ty; + + quote! { + <#field_type as #core::codec::Decode>::decode_iter(iter)? + } + }); + + quote! { + return Ok(Self::#variant_ident( #(#field_impls),* )); + } + } + Fields::Unit => { + quote! { + return Ok(Self::#variant_ident); + } + } + }; + + quote! { + if tag == &#ind_variant { + #decode_impl + } + } + }); + + let ident = ident.to_string(); + + quote! { + let tag = iter.next().ok_or_else(#core::codec::Error::input_exhausted)?; + + #(#variant_impls)* + + Err(#core::codec::Error::unknown_enum_tag(tag, #ident)) + } + } + syn::Data::Union(_) => panic!("union type not supported"), + }; + + quote! { + #[automatically_derived] + impl<'a> #core::codec::Decode<'a> for #ident { + fn decode_iter(iter: &mut T) -> ::core::result::Result + where + T: core::iter::Iterator + { + #impl_block + } + } + } + .into() +} + +/// Determines the path to the `starknet-core` crate root. +fn derive_core_path(input: &DeriveInput) -> proc_macro2::TokenStream { + let mut attr_args = Args::default(); + + for attr in &input.attrs { + if !attr.meta.path().is_ident("starknet") { + continue; + } + + match &attr.meta { + Meta::Path(_) => {} + Meta::List(meta_list) => { + let args: Args = meta_list + .parse_args() + .expect("unable to parse starknet attribute args"); + + attr_args.merge(args); + } + Meta::NameValue(_) => panic!("starknet attribute must not be name-value"), + } + } + + attr_args.core.map_or_else( + || { + #[cfg(not(feature = "import_from_starknet"))] + quote! { + ::starknet_core + } + + // This feature is enabled by the `starknet` crate. When using `starknet` it's assumed + // that users would not have imported `starknet-core` directly. + #[cfg(feature = "import_from_starknet")] + quote! { + ::starknet::core + } + }, + |id| id.parse().expect("unable to parse core crate path"), + ) +} + +/// Turns an integer into an optimal `TokenStream` that constructs a `Felt` with the same value. +fn int_to_felt(int: usize, core: &proc_macro2::TokenStream) -> proc_macro2::TokenStream { + match int { + 0 => quote! { #core::types::Felt::ZERO }, + 1 => quote! { #core::types::Felt::ONE }, + 2 => quote! { #core::types::Felt::TWO }, + 3 => quote! { #core::types::Felt::THREE }, + // TODO: turn the number into Montgomery repr and use const ctor instead. + _ => { + let literal = LitInt::new(&int.to_string(), Span::call_site()); + quote! { #core::types::Felt::from(#literal) } + } + } +} diff --git a/starknet-core/Cargo.toml b/starknet-core/Cargo.toml index f3302ac2..5b0b1eac 100644 --- a/starknet-core/Cargo.toml +++ b/starknet-core/Cargo.toml @@ -18,10 +18,12 @@ all-features = true [dependencies] starknet-crypto = { version = "0.7.2", path = "../starknet-crypto", default-features = false, features = ["alloc"] } +starknet-core-derive = { version = "0.1.0", path = "../starknet-core-derive" } base64 = { version = "0.21.0", default-features = false, features = ["alloc"] } crypto-bigint = { version = "0.5.1", default-features = false } flate2 = { version = "1.0.25", optional = true } hex = { version = "0.4.3", default-features = false, features = ["alloc"] } +num-traits = { version = "0.2.19", default-features = false } serde = { version = "1.0.160", default-features = false, features = ["derive"] } serde_json = { version = "1.0.96", default-features = false, features = ["alloc", "raw_value"] } serde_json_pythonic = { version = "0.1.2", default-features = false, features = ["alloc", "raw_value"] } diff --git a/starknet-core/src/codec.rs b/starknet-core/src/codec.rs new file mode 100644 index 00000000..0cc60f6e --- /dev/null +++ b/starknet-core/src/codec.rs @@ -0,0 +1,747 @@ +use alloc::{boxed::Box, fmt::Formatter, format, string::*, vec::*}; +use core::fmt::Display; + +use num_traits::ToPrimitive; + +use crate::types::{Felt, U256}; + +pub use starknet_core_derive::{Decode, Encode}; + +/// Any type where [`Felt`]s can be written into. This would typically be [`Vec`], but can +/// also be something like a stateful hasher. +/// +/// The trait method is infallible, as the most common use case is to simply write into a `Vec`. +/// Making the method infallible avoids over-engineering. However, if deemed necessary, a future +/// breaking change can make this fallible instead. +pub trait FeltWriter { + /// Adds a single [Felt] element into the writer. + fn write(&mut self, felt: Felt); +} + +/// Any type that can be serialized into a series of [Felt]s. This trait corresponds to the +/// `serialize` function of the Cairo `Serde` trait. +pub trait Encode { + /// Converts the type into a list of [`Felt`] and append them into the writer. + fn encode(&self, writer: &mut W) -> Result<(), Error>; +} + +/// Any type that can be deserialized from a series of [Felt]s. This trait corresponds to the +/// `deserialize` function of the Cairo `Serde` trait. +pub trait Decode<'a>: Sized { + /// Converts into the type from a list of [`Felt`]. + fn decode(reader: T) -> Result + where + T: IntoIterator, + { + Self::decode_iter(&mut reader.into_iter()) + } + + /// Converts into the type from an iterator of references to [`Felt`]. + fn decode_iter(iter: &mut T) -> Result + where + T: Iterator; +} + +/// Error type for any encoding/decoding operations. +/// +/// A simple string representation is forced onto all implementations for simplicity. This is +/// because most of the time, a encoding/decoding error indicates a bug that requires human +/// attention to fix anyway; even when handling untrusted data, the program is likely to only be +/// interested in knowing that an error _did_ occur, instead of handling based on cause. +/// +/// There might be cases where allocations must be avoided. A feature could be added in the future +/// that turns the `repr` into `()` to address this. Such a feature would be a non-breaking change +/// so there's no need to add it now. +#[derive(Debug)] +pub struct Error { + repr: Box, +} + +impl FeltWriter for Vec { + fn write(&mut self, felt: Felt) { + self.push(felt); + } +} + +impl Encode for Felt { + fn encode(&self, writer: &mut W) -> Result<(), Error> { + writer.write(*self); + Ok(()) + } +} + +impl Encode for bool { + fn encode(&self, writer: &mut W) -> Result<(), Error> { + writer.write(if *self { Felt::ONE } else { Felt::ZERO }); + Ok(()) + } +} + +impl Encode for u8 { + fn encode(&self, writer: &mut W) -> Result<(), Error> { + writer.write((*self).into()); + Ok(()) + } +} + +impl Encode for u16 { + fn encode(&self, writer: &mut W) -> Result<(), Error> { + writer.write((*self).into()); + Ok(()) + } +} + +impl Encode for u32 { + fn encode(&self, writer: &mut W) -> Result<(), Error> { + writer.write((*self).into()); + Ok(()) + } +} + +impl Encode for u64 { + fn encode(&self, writer: &mut W) -> Result<(), Error> { + writer.write((*self).into()); + Ok(()) + } +} + +impl Encode for u128 { + fn encode(&self, writer: &mut W) -> Result<(), Error> { + writer.write((*self).into()); + Ok(()) + } +} + +impl Encode for U256 { + fn encode(&self, writer: &mut W) -> Result<(), Error> { + self.low().encode(writer)?; + self.high().encode(writer)?; + Ok(()) + } +} + +impl Encode for Option +where + T: Encode, +{ + fn encode(&self, writer: &mut W) -> Result<(), Error> { + match self { + Some(inner) => { + writer.write(Felt::ZERO); + inner.encode(writer)?; + } + None => { + writer.write(Felt::ONE); + } + } + + Ok(()) + } +} + +impl<'a> Decode<'a> for Felt { + fn decode_iter(iter: &mut T) -> Result + where + T: Iterator, + { + iter.next().ok_or_else(Error::input_exhausted).cloned() + } +} + +impl<'a> Decode<'a> for bool { + fn decode_iter(iter: &mut T) -> Result + where + T: Iterator, + { + let input = iter.next().ok_or_else(Error::input_exhausted)?; + if input == &Felt::ZERO { + Ok(false) + } else if input == &Felt::ONE { + Ok(true) + } else { + Err(Error::value_out_of_range(input, "bool")) + } + } +} + +impl<'a> Decode<'a> for u8 { + fn decode_iter(iter: &mut T) -> Result + where + T: Iterator, + { + let input = iter.next().ok_or_else(Error::input_exhausted)?; + input + .to_u8() + .ok_or_else(|| Error::value_out_of_range(input, "u8")) + } +} + +impl<'a> Decode<'a> for u16 { + fn decode_iter(iter: &mut T) -> Result + where + T: Iterator, + { + let input = iter.next().ok_or_else(Error::input_exhausted)?; + input + .to_u16() + .ok_or_else(|| Error::value_out_of_range(input, "u16")) + } +} + +impl<'a> Decode<'a> for u32 { + fn decode_iter(iter: &mut T) -> Result + where + T: Iterator, + { + let input = iter.next().ok_or_else(Error::input_exhausted)?; + input + .to_u32() + .ok_or_else(|| Error::value_out_of_range(input, "u32")) + } +} + +impl<'a> Decode<'a> for u64 { + fn decode_iter(iter: &mut T) -> Result + where + T: Iterator, + { + let input = iter.into_iter().next().ok_or_else(Error::input_exhausted)?; + input + .to_u64() + .ok_or_else(|| Error::value_out_of_range(input, "u64")) + } +} + +impl<'a> Decode<'a> for u128 { + fn decode_iter(iter: &mut T) -> Result + where + T: Iterator, + { + let input = iter.next().ok_or_else(Error::input_exhausted)?; + input + .to_u128() + .ok_or_else(|| Error::value_out_of_range(input, "u128")) + } +} + +impl<'a> Decode<'a> for U256 { + fn decode_iter(iter: &mut T) -> Result + where + T: Iterator, + { + let input_low = iter.next().ok_or_else(Error::input_exhausted)?; + let input_high = iter.next().ok_or_else(Error::input_exhausted)?; + + let input_low = input_low + .to_u128() + .ok_or_else(|| Error::value_out_of_range(input_low, "u128"))?; + let input_high = input_high + .to_u128() + .ok_or_else(|| Error::value_out_of_range(input_high, "u128"))?; + + Ok(Self::from_words(input_low, input_high)) + } +} + +impl<'a, T> Decode<'a> for Option +where + T: Decode<'a>, +{ + fn decode_iter(iter: &mut I) -> Result + where + I: Iterator, + { + let tag = iter.next().ok_or_else(Error::input_exhausted)?; + + if tag == &Felt::ZERO { + Ok(Some(T::decode_iter(iter)?)) + } else if tag == &Felt::ONE { + Ok(None) + } else { + Err(Error::unknown_enum_tag(tag, "Option")) + } + } +} + +impl Error { + /// Creates an [`Error`] which indicates that the input stream has ended prematurely. + pub fn input_exhausted() -> Self { + Self { + repr: "unexpected end of input stream" + .to_string() + .into_boxed_str(), + } + } + + /// Creates an [`Error`] which indicates that the input value is out of range. + pub fn value_out_of_range(value: V, type_name: &str) -> Self + where + V: Display, + { + Self { + repr: format!("value `{}` is out of range for type `{}`", value, type_name) + .into_boxed_str(), + } + } + + /// Creates an [`Error`] which indicates that the enum tag does not belong to a known variant. + pub fn unknown_enum_tag(tag: V, type_name: &str) -> Self + where + V: Display, + { + Self { + repr: format!("enum tag `{}` is unknown for type `{}`", tag, type_name) + .into_boxed_str(), + } + } + + /// Creates an [`Error`] using a custom error string. + pub fn custom(content: T) -> Self + where + T: Display, + { + Self { + repr: content.to_string().into_boxed_str(), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.repr) + } +} + +#[cfg(test)] +mod tests { + use core::str::FromStr; + + use super::*; + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_felt() { + let mut serialized = Vec::::new(); + Felt::from_str("99999999999999999999999999") + .unwrap() + .encode(&mut serialized) + .unwrap(); + assert_eq!( + serialized, + vec![Felt::from_str("99999999999999999999999999").unwrap()] + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_bool() { + let mut serialized = Vec::::new(); + true.encode(&mut serialized).unwrap(); + assert_eq!(serialized, vec![Felt::from_str("1").unwrap()]); + + let mut serialized = Vec::::new(); + false.encode(&mut serialized).unwrap(); + assert_eq!(serialized, vec![Felt::from_str("0").unwrap()]); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_u8() { + let mut serialized = Vec::::new(); + 123u8.encode(&mut serialized).unwrap(); + assert_eq!(serialized, vec![Felt::from_str("123").unwrap()]); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_u16() { + let mut serialized = Vec::::new(); + 12345u16.encode(&mut serialized).unwrap(); + assert_eq!(serialized, vec![Felt::from_str("12345").unwrap()]); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_u32() { + let mut serialized = Vec::::new(); + 1234567890u32.encode(&mut serialized).unwrap(); + assert_eq!(serialized, vec![Felt::from_str("1234567890").unwrap()]); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_u64() { + let mut serialized = Vec::::new(); + 12345678900000000000u64.encode(&mut serialized).unwrap(); + assert_eq!( + serialized, + vec![Felt::from_str("12345678900000000000").unwrap()] + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_u128() { + let mut serialized = Vec::::new(); + 123456789000000000000000000000u128 + .encode(&mut serialized) + .unwrap(); + assert_eq!( + serialized, + vec![Felt::from_str("123456789000000000000000000000").unwrap()] + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_u256() { + let mut serialized = Vec::::new(); + U256::from_words(12345, 67890) + .encode(&mut serialized) + .unwrap(); + assert_eq!( + serialized, + vec![ + Felt::from_str("12345").unwrap(), + Felt::from_str("67890").unwrap() + ] + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_option() { + let mut serialized = Vec::::new(); + Some(10u32).encode(&mut serialized).unwrap(); + assert_eq!( + serialized, + vec![Felt::from_str("0").unwrap(), Felt::from_str("10").unwrap()] + ); + + serialized.clear(); + Option::::None.encode(&mut serialized).unwrap(); + assert_eq!(serialized, vec![Felt::from_str("1").unwrap()]); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_derive_encode_struct_named() { + #[derive(Encode)] + #[starknet(core = "crate")] + struct CairoType { + a: Felt, + b: U256, + c: bool, + } + + let mut serialized = Vec::::new(); + CairoType { + a: Felt::from_str("12345").unwrap(), + b: U256::from_words(12, 34), + c: true, + } + .encode(&mut serialized) + .unwrap(); + assert_eq!( + serialized, + vec![ + Felt::from_str("12345").unwrap(), + Felt::from_str("12").unwrap(), + Felt::from_str("34").unwrap(), + Felt::from_str("1").unwrap(), + ] + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_derive_encode_struct_tuple() { + #[derive(Encode)] + #[starknet(core = "crate")] + struct CairoType(Felt, U256, bool); + + let mut serialized = Vec::::new(); + CairoType( + Felt::from_str("12345").unwrap(), + U256::from_words(12, 34), + true, + ) + .encode(&mut serialized) + .unwrap(); + assert_eq!( + serialized, + vec![ + Felt::from_str("12345").unwrap(), + Felt::from_str("12").unwrap(), + Felt::from_str("34").unwrap(), + Felt::from_str("1").unwrap(), + ] + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_derive_encode_enum() { + #[derive(Encode)] + #[starknet(core = "crate")] + enum CairoType { + A, + B(bool), + C(Option, u8), + D { a: u64, b: bool }, + } + + let mut serialized = Vec::::new(); + CairoType::A.encode(&mut serialized).unwrap(); + assert_eq!(serialized, vec![Felt::from_str("0").unwrap()]); + + serialized.clear(); + CairoType::B(true).encode(&mut serialized).unwrap(); + assert_eq!( + serialized, + vec![Felt::from_str("1").unwrap(), Felt::from_str("1").unwrap()] + ); + + serialized.clear(); + CairoType::C(Some(U256::from_words(12, 23)), 4) + .encode(&mut serialized) + .unwrap(); + assert_eq!( + serialized, + vec![ + Felt::from_str("2").unwrap(), + Felt::from_str("0").unwrap(), + Felt::from_str("12").unwrap(), + Felt::from_str("23").unwrap(), + Felt::from_str("4").unwrap(), + ] + ); + + serialized.clear(); + CairoType::C(None, 8).encode(&mut serialized).unwrap(); + assert_eq!( + serialized, + vec![ + Felt::from_str("2").unwrap(), + Felt::from_str("1").unwrap(), + Felt::from_str("8").unwrap(), + ] + ); + + serialized.clear(); + CairoType::D { a: 100, b: false } + .encode(&mut serialized) + .unwrap(); + assert_eq!( + serialized, + vec![ + Felt::from_str("3").unwrap(), + Felt::from_str("100").unwrap(), + Felt::from_str("0").unwrap() + ] + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_decode_felt() { + assert_eq!( + Felt::from_str("99999999999999999999999999").unwrap(), + Felt::decode(&[Felt::from_str("99999999999999999999999999").unwrap()]).unwrap() + ); + } + + #[allow(clippy::bool_assert_comparison)] + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_decode_bool() { + assert_eq!(true, bool::decode(&[Felt::from_str("1").unwrap()]).unwrap()); + + assert_eq!( + false, + bool::decode(&[Felt::from_str("0").unwrap()]).unwrap() + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_decode_u8() { + assert_eq!( + 123u8, + u8::decode(&[Felt::from_str("123").unwrap()]).unwrap() + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_decode_u16() { + assert_eq!( + 12345u16, + u16::decode(&[Felt::from_str("12345").unwrap()]).unwrap() + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_decode_u32() { + assert_eq!( + 1234567890u32, + u32::decode(&[Felt::from_str("1234567890").unwrap()]).unwrap() + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_decode_u64() { + assert_eq!( + 12345678900000000000u64, + u64::decode(&[Felt::from_str("12345678900000000000").unwrap()]).unwrap() + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_decode_u128() { + assert_eq!( + 123456789000000000000000000000u128, + u128::decode(&[Felt::from_str("123456789000000000000000000000").unwrap()]).unwrap() + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_decode_u256() { + assert_eq!( + U256::from_words(12345, 67890), + U256::decode(&[ + Felt::from_str("12345").unwrap(), + Felt::from_str("67890").unwrap() + ]) + .unwrap() + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_decode_option() { + assert_eq!( + Some(10u32), + Option::::decode(&[Felt::from_str("0").unwrap(), Felt::from_str("10").unwrap()]) + .unwrap() + ); + + assert_eq!( + Option::::None, + Option::::decode(&[Felt::from_str("1").unwrap()]).unwrap() + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_derive_decode_struct_named() { + #[derive(Debug, PartialEq, Eq, Decode)] + #[starknet(core = "crate")] + struct CairoType { + a: Felt, + b: U256, + c: bool, + } + + assert_eq!( + CairoType { + a: Felt::from_str("12345").unwrap(), + b: U256::from_words(12, 34), + c: true, + }, + CairoType::decode(&[ + Felt::from_str("12345").unwrap(), + Felt::from_str("12").unwrap(), + Felt::from_str("34").unwrap(), + Felt::from_str("1").unwrap(), + ]) + .unwrap() + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_derive_decode_struct_tuple() { + #[derive(Debug, PartialEq, Eq, Decode)] + #[starknet(core = "crate")] + struct CairoType(Felt, U256, bool); + + assert_eq!( + CairoType( + Felt::from_str("12345").unwrap(), + U256::from_words(12, 34), + true, + ), + CairoType::decode(&[ + Felt::from_str("12345").unwrap(), + Felt::from_str("12").unwrap(), + Felt::from_str("34").unwrap(), + Felt::from_str("1").unwrap(), + ]) + .unwrap() + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_derive_decode_enum() { + #[derive(Debug, PartialEq, Eq, Decode)] + #[starknet(core = "crate")] + enum CairoType { + A, + B(bool), + C(Option, u8), + D { a: u64, b: bool }, + } + + assert_eq!( + CairoType::A, + CairoType::decode(&[Felt::from_str("0").unwrap()]).unwrap() + ); + + assert_eq!( + CairoType::B(true), + CairoType::decode(&[Felt::from_str("1").unwrap(), Felt::from_str("1").unwrap()]) + .unwrap() + ); + + assert_eq!( + CairoType::C(Some(U256::from_words(12, 23)), 4), + CairoType::decode(&[ + Felt::from_str("2").unwrap(), + Felt::from_str("0").unwrap(), + Felt::from_str("12").unwrap(), + Felt::from_str("23").unwrap(), + Felt::from_str("4").unwrap(), + ]) + .unwrap() + ); + + assert_eq!( + CairoType::C(None, 8), + CairoType::decode(&[ + Felt::from_str("2").unwrap(), + Felt::from_str("1").unwrap(), + Felt::from_str("8").unwrap(), + ]) + .unwrap() + ); + + assert_eq!( + CairoType::D { a: 100, b: false }, + CairoType::decode(&[ + Felt::from_str("3").unwrap(), + Felt::from_str("100").unwrap(), + Felt::from_str("0").unwrap() + ]) + .unwrap() + ); + } +} diff --git a/starknet-core/src/lib.rs b/starknet-core/src/lib.rs index 676c1bed..88eb2e90 100644 --- a/starknet-core/src/lib.rs +++ b/starknet-core/src/lib.rs @@ -19,4 +19,7 @@ pub mod utils; /// Chain IDs for commonly used public Starknet networks. pub mod chain_id; +/// Types for serializing high-level Cairo types into field elements and vice versa. +pub mod codec; + extern crate alloc; From d7a5feb43721862d687b025c1951af7b83351bf7 Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Mon, 21 Oct 2024 05:38:53 +0200 Subject: [PATCH 45/54] feat: derive `Clone` for `HttpTransport` and `JsonRpcClient` (#666) --- starknet-providers/src/jsonrpc/mod.rs | 2 +- starknet-providers/src/jsonrpc/transports/http.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/starknet-providers/src/jsonrpc/mod.rs b/starknet-providers/src/jsonrpc/mod.rs index 1f91e070..211bd3b7 100644 --- a/starknet-providers/src/jsonrpc/mod.rs +++ b/starknet-providers/src/jsonrpc/mod.rs @@ -30,7 +30,7 @@ pub use transports::{HttpTransport, HttpTransportError, JsonRpcTransport}; /// /// A "transport" is any implementation that can send JSON-RPC requests and receive responses. This /// most commonly happens over a network via HTTP connections, as with [`HttpTransport`]. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct JsonRpcClient { transport: T, } diff --git a/starknet-providers/src/jsonrpc/transports/http.rs b/starknet-providers/src/jsonrpc/transports/http.rs index bf85ca0f..fb7e6120 100644 --- a/starknet-providers/src/jsonrpc/transports/http.rs +++ b/starknet-providers/src/jsonrpc/transports/http.rs @@ -9,7 +9,7 @@ use crate::{ }; /// A [`JsonRpcTransport`] implementation that uses HTTP connections. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct HttpTransport { client: Client, url: Url, From 21ddb93069b2cee67c0b49967ba5f89987a8f01c Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 21 Oct 2024 18:13:42 +0800 Subject: [PATCH 46/54] feat: implement `Encode` and `Decode` for primitive collection types (#670) --- examples/serde.rs | 18 +++- starknet-core/src/codec.rs | 183 ++++++++++++++++++++++++++++++++++++- 2 files changed, 197 insertions(+), 4 deletions(-) diff --git a/examples/serde.rs b/examples/serde.rs index 4c80d530..63f9c843 100644 --- a/examples/serde.rs +++ b/examples/serde.rs @@ -10,14 +10,16 @@ use starknet::{ struct CairoType { a: Felt, b: Option, - c: bool, + c: Vec, + d: [u8; 2], } fn main() { let instance = CairoType { a: felt!("123456789"), b: Some(100), - c: false, + c: vec![false, true], + d: [3, 4], }; let mut serialized = vec![]; @@ -25,7 +27,17 @@ fn main() { assert_eq!( serialized, - [felt!("123456789"), felt!("0"), felt!("100"), felt!("0")] + [ + felt!("123456789"), + felt!("0"), + felt!("100"), + felt!("2"), + felt!("0"), + felt!("1"), + felt!("2"), + felt!("3"), + felt!("4"), + ] ); let restored = CairoType::decode(&serialized).unwrap(); diff --git a/starknet-core/src/codec.rs b/starknet-core/src/codec.rs index 0cc60f6e..b5ab08fb 100644 --- a/starknet-core/src/codec.rs +++ b/starknet-core/src/codec.rs @@ -1,5 +1,5 @@ use alloc::{boxed::Box, fmt::Formatter, format, string::*, vec::*}; -use core::fmt::Display; +use core::{fmt::Display, mem::MaybeUninit}; use num_traits::ToPrimitive; @@ -139,6 +139,51 @@ where } } +impl Encode for Vec +where + T: Encode, +{ + fn encode(&self, writer: &mut W) -> Result<(), Error> { + writer.write(Felt::from(self.len())); + + for item in self { + item.encode(writer)?; + } + + Ok(()) + } +} + +impl Encode for [T; N] +where + T: Encode, +{ + fn encode(&self, writer: &mut W) -> Result<(), Error> { + writer.write(Felt::from(N)); + + for item in self { + item.encode(writer)?; + } + + Ok(()) + } +} + +impl Encode for [T] +where + T: Encode, +{ + fn encode(&self, writer: &mut W) -> Result<(), Error> { + writer.write(Felt::from(self.len())); + + for item in self { + item.encode(writer)?; + } + + Ok(()) + } +} + impl<'a> Decode<'a> for Felt { fn decode_iter(iter: &mut T) -> Result where @@ -263,6 +308,56 @@ where } } +impl<'a, T> Decode<'a> for Vec +where + T: Decode<'a>, +{ + fn decode_iter(iter: &mut I) -> Result + where + I: Iterator, + { + let length = iter.next().ok_or_else(Error::input_exhausted)?; + let length = length + .to_usize() + .ok_or_else(|| Error::value_out_of_range(length, "usize"))?; + + let mut result = Self::with_capacity(length); + + for _ in 0..length { + result.push(T::decode_iter(iter)?); + } + + Ok(result) + } +} + +impl<'a, T, const N: usize> Decode<'a> for [T; N] +where + T: Decode<'a> + Sized, +{ + fn decode_iter(iter: &mut I) -> Result + where + I: Iterator, + { + let length = iter.next().ok_or_else(Error::input_exhausted)?; + let length = length + .to_usize() + .ok_or_else(|| Error::value_out_of_range(length, "usize"))?; + + if length != N { + return Err(Error::length_mismatch(N, length)); + } + + let mut result: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; + + for elem in &mut result[..] { + *elem = MaybeUninit::new(T::decode_iter(iter)?); + } + + Ok(unsafe { core::mem::transmute_copy::<_, [T; N]>(&result) }) + } +} + impl Error { /// Creates an [`Error`] which indicates that the input stream has ended prematurely. pub fn input_exhausted() -> Self { @@ -273,6 +368,14 @@ impl Error { } } + /// Creates an [`Error`] which indicates that the length (likely prefix) is different from the + /// expected value. + pub fn length_mismatch(expected: usize, actual: usize) -> Self { + Self { + repr: format!("expecting length `{}` but got `{}`", expected, actual).into_boxed_str(), + } + } + /// Creates an [`Error`] which indicates that the input value is out of range. pub fn value_out_of_range(value: V, type_name: &str) -> Self where @@ -426,6 +529,54 @@ mod tests { assert_eq!(serialized, vec![Felt::from_str("1").unwrap()]); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_vec() { + let mut serialized = Vec::::new(); + vec![Some(10u32), None].encode(&mut serialized).unwrap(); + assert_eq!( + serialized, + vec![ + Felt::from_str("2").unwrap(), + Felt::from_str("0").unwrap(), + Felt::from_str("10").unwrap(), + Felt::from_str("1").unwrap() + ] + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_array() { + let mut serialized = Vec::::new(); + <[Option; 2]>::encode(&[Some(10u32), None], &mut serialized).unwrap(); + assert_eq!( + serialized, + vec![ + Felt::from_str("2").unwrap(), + Felt::from_str("0").unwrap(), + Felt::from_str("10").unwrap(), + Felt::from_str("1").unwrap() + ] + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_encode_slice() { + let mut serialized = Vec::::new(); + <[Option]>::encode(&[Some(10u32), None], &mut serialized).unwrap(); + assert_eq!( + serialized, + vec![ + Felt::from_str("2").unwrap(), + Felt::from_str("0").unwrap(), + Felt::from_str("10").unwrap(), + Felt::from_str("1").unwrap() + ] + ); + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_derive_encode_struct_named() { @@ -639,6 +790,36 @@ mod tests { ); } + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_decode_vec() { + assert_eq!( + vec![Some(10u32), None], + Vec::>::decode(&[ + Felt::from_str("2").unwrap(), + Felt::from_str("0").unwrap(), + Felt::from_str("10").unwrap(), + Felt::from_str("1").unwrap() + ]) + .unwrap() + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn test_decode_array() { + assert_eq!( + [Some(10u32), None], + <[Option; 2]>::decode(&[ + Felt::from_str("2").unwrap(), + Felt::from_str("0").unwrap(), + Felt::from_str("10").unwrap(), + Felt::from_str("1").unwrap() + ]) + .unwrap() + ); + } + #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_derive_decode_struct_named() { From fde32dc485dde51238ebed94fd5cde6a5689602c Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Tue, 22 Oct 2024 23:04:08 +0800 Subject: [PATCH 47/54] ci: remove cargo-udeps workflow (#673) --- .github/workflows/udeps.yml | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 .github/workflows/udeps.yml diff --git a/.github/workflows/udeps.yml b/.github/workflows/udeps.yml deleted file mode 100644 index 203d0c15..00000000 --- a/.github/workflows/udeps.yml +++ /dev/null @@ -1,35 +0,0 @@ -on: - push: - branches: - - master - pull_request: - -name: Unused deps -jobs: - udeps: - runs-on: ubuntu-latest - steps: - - name: Checkout source code - uses: actions/checkout@v2 - - - name: Setup nightly toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - profile: minimal - override: true - - - uses: Swatinem/rust-cache@v1 - with: - cache-on-failure: true - - - name: Install udeps - uses: actions-rs/cargo@v1 - with: - command: install - args: cargo-udeps - - - name: Run udeps - uses: actions-rs/cargo@v1 - with: - command: udeps From 17c7ef717724a901f6672d1b144de41c4f5d088c Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Wed, 23 Oct 2024 03:12:09 +0800 Subject: [PATCH 48/54] docs: better docs for `Encode` and `Decode` (#672) --- starknet-core/src/codec.rs | 55 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/starknet-core/src/codec.rs b/starknet-core/src/codec.rs index b5ab08fb..6d3b8a11 100644 --- a/starknet-core/src/codec.rs +++ b/starknet-core/src/codec.rs @@ -20,6 +20,34 @@ pub trait FeltWriter { /// Any type that can be serialized into a series of [Felt]s. This trait corresponds to the /// `serialize` function of the Cairo `Serde` trait. +/// +/// This trait can be derived as long as all the fields in type implement [`Encode`]. +/// +/// # Example +/// +/// This example demonstrates deriving the trait and then using it to serialize an instance into +/// [`Vec`]. +/// +/// ```rust +/// use starknet_core::codec::Encode; +/// # use starknet_core::types::Felt; +/// +/// #[derive(Encode)] +/// # #[starknet(core = "starknet_core")] +/// struct CairoType { +/// a: u32, +/// b: Option, +/// } +/// +/// let instance = CairoType { +/// a: 3, +/// b: Some(true), +/// }; +/// let mut serialized = vec![]; +/// instance.encode(&mut serialized); +/// +/// assert_eq!(vec![Felt::THREE, Felt::ZERO, Felt::ONE], serialized); +/// ``` pub trait Encode { /// Converts the type into a list of [`Felt`] and append them into the writer. fn encode(&self, writer: &mut W) -> Result<(), Error>; @@ -27,6 +55,33 @@ pub trait Encode { /// Any type that can be deserialized from a series of [Felt]s. This trait corresponds to the /// `deserialize` function of the Cairo `Serde` trait. +/// +/// This trait can be derived as long as all the fields in type implement [`Encode`]. +/// +/// # Example +/// +/// This example demonstrates deriving the trait and then using it to deserialize an instance from +/// [`Vec`]. +/// +/// ```rust +/// use starknet_core::codec::Decode; +/// # use starknet_core::types::Felt; +/// +/// #[derive(Debug, PartialEq, Eq, Decode)] +/// # #[starknet(core = "starknet_core")] +/// struct CairoType { +/// a: u32, +/// b: Option, +/// } +/// +/// assert_eq!( +/// CairoType { +/// a: 3, +/// b: Some(true) +/// }, +/// CairoType::decode(&[Felt::THREE, Felt::ZERO, Felt::ONE]).unwrap() +/// ); +/// ``` pub trait Decode<'a>: Sized { /// Converts into the type from a list of [`Felt`]. fn decode(reader: T) -> Result From 38e4360fa577d605c8ce02607e8ebee977eb1047 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 4 Nov 2024 10:39:51 -0700 Subject: [PATCH 49/54] chore: make nightly clippy happy (#676) --- starknet-accounts/src/account/declaration.rs | 6 +++--- starknet-accounts/src/account/execution.rs | 4 ++-- starknet-accounts/src/factory/mod.rs | 4 ++-- starknet-contract/src/factory.rs | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/starknet-accounts/src/account/declaration.rs b/starknet-accounts/src/account/declaration.rs index 4fff8855..b47296fa 100644 --- a/starknet-accounts/src/account/declaration.rs +++ b/starknet-accounts/src/account/declaration.rs @@ -1019,7 +1019,7 @@ where } } -impl<'a, A> PreparedDeclarationV2<'a, A> +impl PreparedDeclarationV2<'_, A> where A: ConnectedAccount, { @@ -1069,7 +1069,7 @@ where } } -impl<'a, A> PreparedDeclarationV3<'a, A> +impl PreparedDeclarationV3<'_, A> where A: ConnectedAccount, { @@ -1138,7 +1138,7 @@ where } } -impl<'a, A> PreparedLegacyDeclaration<'a, A> +impl PreparedLegacyDeclaration<'_, A> where A: ConnectedAccount, { diff --git a/starknet-accounts/src/account/execution.rs b/starknet-accounts/src/account/execution.rs index 00aa956b..4c019c01 100644 --- a/starknet-accounts/src/account/execution.rs +++ b/starknet-accounts/src/account/execution.rs @@ -762,7 +762,7 @@ where } } -impl<'a, A> PreparedExecutionV1<'a, A> +impl PreparedExecutionV1<'_, A> where A: ConnectedAccount, { @@ -804,7 +804,7 @@ where } } -impl<'a, A> PreparedExecutionV3<'a, A> +impl PreparedExecutionV3<'_, A> where A: ConnectedAccount, { diff --git a/starknet-accounts/src/factory/mod.rs b/starknet-accounts/src/factory/mod.rs index b893abc3..e1d7d09c 100644 --- a/starknet-accounts/src/factory/mod.rs +++ b/starknet-accounts/src/factory/mod.rs @@ -881,7 +881,7 @@ impl<'f, F> PreparedAccountDeploymentV3<'f, F> { } } -impl<'f, F> PreparedAccountDeploymentV1<'f, F> +impl PreparedAccountDeploymentV1<'_, F> where F: AccountFactory, { @@ -953,7 +953,7 @@ where } } -impl<'f, F> PreparedAccountDeploymentV3<'f, F> +impl PreparedAccountDeploymentV3<'_, F> where F: AccountFactory, { diff --git a/starknet-contract/src/factory.rs b/starknet-contract/src/factory.rs index cc93aa01..a3a8ff64 100644 --- a/starknet-contract/src/factory.rs +++ b/starknet-contract/src/factory.rs @@ -257,7 +257,7 @@ where } } -impl<'f, A> DeploymentV1<'f, A> +impl DeploymentV1<'_, A> where A: ConnectedAccount + Sync, { @@ -285,7 +285,7 @@ where } } -impl<'f, A> DeploymentV3<'f, A> +impl DeploymentV3<'_, A> where A: ConnectedAccount + Sync, { From 2291904921015d226c6a1d1fc12e7884c762d214 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 4 Nov 2024 20:37:42 -0700 Subject: [PATCH 50/54] feat: alternative (slow) pedersen hash impl optimized for size (#675) --- .github/workflows/test.yaml | 8 ++ starknet-crypto/Cargo.toml | 1 + starknet-crypto/README.md | 8 ++ starknet-crypto/src/pedersen_hash/default.rs | 14 +++ .../mod.rs} | 21 ++-- .../src/pedersen_hash/no_lookup.rs | 97 +++++++++++++++++++ 6 files changed, 136 insertions(+), 13 deletions(-) create mode 100644 starknet-crypto/src/pedersen_hash/default.rs rename starknet-crypto/src/{pedersen_hash.rs => pedersen_hash/mod.rs} (80%) create mode 100644 starknet-crypto/src/pedersen_hash/no_lookup.rs diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b3b9c8a6..62c058ca 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -25,6 +25,10 @@ jobs: profile: minimal override: true + - name: Test starknet-crypto with pedersen_no_lookup + run: | + cargo test -p starknet-crypto --features pedersen_no_lookup + - name: Run cargo tests uses: nick-fields/retry@v2 with: @@ -53,6 +57,10 @@ jobs: profile: minimal override: true + - name: Test starknet-crypto with pedersen_no_lookup + run: | + cargo test -p starknet-crypto --features pedersen_no_lookup + - name: Run cargo tests uses: nick-fields/retry@v2 with: diff --git a/starknet-crypto/Cargo.toml b/starknet-crypto/Cargo.toml index b0989925..23c46487 100644 --- a/starknet-crypto/Cargo.toml +++ b/starknet-crypto/Cargo.toml @@ -31,6 +31,7 @@ default = ["std", "signature-display"] std = ["starknet-types-core/std"] alloc = ["hex?/alloc", "starknet-types-core/alloc"] signature-display = ["dep:hex", "alloc"] +pedersen_no_lookup = [] [dev-dependencies] criterion = { version = "0.4.0", default-features = false } diff --git a/starknet-crypto/README.md b/starknet-crypto/README.md index 3af6bc0e..32e92fca 100644 --- a/starknet-crypto/README.md +++ b/starknet-crypto/README.md @@ -65,6 +65,14 @@ poseidon_hash_many time: [41.878 µs 41.911 µs 41.945 µs] rfc6979_generate_k time: [11.564 µs 11.566 µs 11.569 µs] ``` +## Binary size optimization + +By default, `starknet-crypto` ships with a Pedersen hash implementation utilizing a lookup table for better performance. To optimize for binary size over performance, the crate offers a `pedersen_no_lookup` feature, which uses a vanilla unoptimized implementation instead. + +> [!WARNING] +> +> Enabling the `pedersen_no_lookup` feature significantly slows down hashing performance by approximately a factor of `10`. Make sure you understand the impact on your use case before turning it on. + ## Credits Most of the code in this crate for the Pedersen hash implementation was inspired and modified from the awesome [`pathfinder` from Equilibrium](https://github.com/eqlabs/pathfinder/blob/b091cb889e624897dbb0cbec3c1df9a9e411eb1e/crates/pedersen/src/lib.rs). diff --git a/starknet-crypto/src/pedersen_hash/default.rs b/starknet-crypto/src/pedersen_hash/default.rs new file mode 100644 index 00000000..21279a76 --- /dev/null +++ b/starknet-crypto/src/pedersen_hash/default.rs @@ -0,0 +1,14 @@ +use starknet_types_core::{ + felt::Felt, + hash::{Pedersen, StarkHash}, +}; + +/// Computes the Starkware version of the Pedersen hash of x and y. All inputs are little-endian. +/// +/// ### Parameters +/// +/// - `x`: The x coordinate. +/// - `y`: The y coordinate. +pub fn pedersen_hash(x: &Felt, y: &Felt) -> Felt { + Pedersen::hash(x, y) +} diff --git a/starknet-crypto/src/pedersen_hash.rs b/starknet-crypto/src/pedersen_hash/mod.rs similarity index 80% rename from starknet-crypto/src/pedersen_hash.rs rename to starknet-crypto/src/pedersen_hash/mod.rs index 275b5d81..c6d01a59 100644 --- a/starknet-crypto/src/pedersen_hash.rs +++ b/starknet-crypto/src/pedersen_hash/mod.rs @@ -1,17 +1,12 @@ -use starknet_types_core::{ - felt::Felt, - hash::{Pedersen, StarkHash}, -}; +#[cfg(not(feature = "pedersen_no_lookup"))] +mod default; +#[cfg(not(feature = "pedersen_no_lookup"))] +pub use default::pedersen_hash; -/// Computes the Starkware version of the Pedersen hash of x and y. All inputs are little-endian. -/// -/// ### Parameters -/// -/// - `x`: The x coordinate. -/// - `y`: The y coordinate. -pub fn pedersen_hash(x: &Felt, y: &Felt) -> Felt { - Pedersen::hash(x, y) -} +#[cfg(feature = "pedersen_no_lookup")] +mod no_lookup; +#[cfg(feature = "pedersen_no_lookup")] +pub use no_lookup::pedersen_hash; #[cfg(test)] mod tests { diff --git a/starknet-crypto/src/pedersen_hash/no_lookup.rs b/starknet-crypto/src/pedersen_hash/no_lookup.rs new file mode 100644 index 00000000..b999a451 --- /dev/null +++ b/starknet-crypto/src/pedersen_hash/no_lookup.rs @@ -0,0 +1,97 @@ +// Size-optimized implementation ported from: +// https://github.com/andrewmilson/sandstorm/blob/9e256c4933aa2d89f794b3ed7c293b32984fe1ce/builtins/src/pedersen/mod.rs#L24-L50 + +use starknet_curve::curve_params::SHIFT_POINT; +use starknet_types_core::{curve::ProjectivePoint, felt::Felt}; + +/// Computes the Starkware version of the Pedersen hash of x and y. All inputs are little-endian. +/// +/// ### Parameters +/// +/// - `x`: The x coordinate. +/// - `y`: The y coordinate. +pub fn pedersen_hash(x: &Felt, y: &Felt) -> Felt { + // Temporarily defining the projective points inline, as `ProjectivePoint::new()` is incorrectly + // not `const`. + // TODO: turn these into consts once upstream is fixed. + let p0_projective: ProjectivePoint = ProjectivePoint::new( + Felt::from_raw([ + 241691544791834578, + 518715844721862878, + 13758484295849329960, + 3602345268353203007, + ]), + Felt::from_raw([ + 368891789801938570, + 433857700841878496, + 13001553326386915570, + 13441546676070136227, + ]), + Felt::ONE, + ); + let p1_projective: ProjectivePoint = ProjectivePoint::new( + Felt::from_raw([ + 253000153565733272, + 10043949394709899044, + 12382025591154462459, + 16491878934996302286, + ]), + Felt::from_raw([ + 285630633187035523, + 5191292837124484988, + 2545498000137298346, + 13950428914333633429, + ]), + Felt::ONE, + ); + let p2_projective: ProjectivePoint = ProjectivePoint::new( + Felt::from_raw([ + 338510149841406402, + 12916675983929588442, + 18195981508842736832, + 1203723169299412240, + ]), + Felt::from_raw([ + 161068411212710156, + 11088962269971685343, + 11743524503750604092, + 12352616181161700245, + ]), + Felt::ONE, + ); + let p3_projective: ProjectivePoint = ProjectivePoint::new( + Felt::from_raw([ + 425493972656615276, + 299781701614706065, + 10664803185694787051, + 1145636535101238356, + ]), + Felt::from_raw([ + 345457391846365716, + 6033691581221864148, + 4428713245976508844, + 8187986478389849302, + ]), + Felt::ONE, + ); + + let processed_x = process_element(x, &p0_projective, &p1_projective); + let processed_y = process_element(y, &p2_projective, &p3_projective); + + // Unwrapping is safe as this never fails + (processed_x + processed_y + SHIFT_POINT) + .to_affine() + .unwrap() + .x() +} + +#[inline(always)] +fn process_element(x: &Felt, p1: &ProjectivePoint, p2: &ProjectivePoint) -> ProjectivePoint { + let x = x.to_biguint(); + let shift = 252 - 4; + let high_part = &x >> shift; + let low_part = x - (&high_part << shift); + let x_high = Felt::from(high_part); + let x_low = Felt::from(low_part); + p1 * x_low + p2 * x_high +} From 5c676a64031901b5a203168fd8ef8d6b40a5862f Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 4 Nov 2024 21:06:08 -0700 Subject: [PATCH 51/54] release: bump starknet-crypto to 0.7.3 (#677) --- Cargo.lock | 2 +- Cargo.toml | 2 +- examples/starknet-wasm/Cargo.toml | 2 +- starknet-accounts/Cargo.toml | 2 +- starknet-core/Cargo.toml | 2 +- starknet-crypto/Cargo.toml | 2 +- starknet-signers/Cargo.toml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 21652b6b..f2df0c1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2117,7 +2117,7 @@ dependencies = [ [[package]] name = "starknet-crypto" -version = "0.7.2" +version = "0.7.3" dependencies = [ "criterion", "crypto-bigint", diff --git a/Cargo.toml b/Cargo.toml index 3e2ad949..87f2d69c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ members = [ all-features = true [dependencies] -starknet-crypto = { version = "0.7.2", path = "./starknet-crypto" } +starknet-crypto = { version = "0.7.3", path = "./starknet-crypto" } starknet-core = { version = "0.12.0", path = "./starknet-core", default-features = false } starknet-core-derive = { version = "0.1.0", path = "./starknet-core-derive", features = ["import_from_starknet"] } starknet-providers = { version = "0.12.0", path = "./starknet-providers" } diff --git a/examples/starknet-wasm/Cargo.toml b/examples/starknet-wasm/Cargo.toml index 15c061bf..31231388 100644 --- a/examples/starknet-wasm/Cargo.toml +++ b/examples/starknet-wasm/Cargo.toml @@ -19,6 +19,6 @@ crate-type = ["cdylib", "rlib"] default = ["console_error_panic_hook"] [dependencies] -starknet-crypto = { version = "0.7.2", path = "../../starknet-crypto" } +starknet-crypto = { version = "0.7.3", path = "../../starknet-crypto" } console_error_panic_hook = { version = "0.1.7", optional = true } wasm-bindgen = "0.2.84" diff --git a/starknet-accounts/Cargo.toml b/starknet-accounts/Cargo.toml index d7a9828f..d25a9ee3 100644 --- a/starknet-accounts/Cargo.toml +++ b/starknet-accounts/Cargo.toml @@ -15,7 +15,7 @@ exclude = ["test-data/**"] [dependencies] starknet-core = { version = "0.12.0", path = "../starknet-core" } -starknet-crypto = { version = "0.7.2", path = "../starknet-crypto" } +starknet-crypto = { version = "0.7.3", path = "../starknet-crypto" } starknet-providers = { version = "0.12.0", path = "../starknet-providers" } starknet-signers = { version = "0.10.0", path = "../starknet-signers" } async-trait = "0.1.68" diff --git a/starknet-core/Cargo.toml b/starknet-core/Cargo.toml index 5b0b1eac..f12658f7 100644 --- a/starknet-core/Cargo.toml +++ b/starknet-core/Cargo.toml @@ -17,7 +17,7 @@ exclude = ["test-data/**"] all-features = true [dependencies] -starknet-crypto = { version = "0.7.2", path = "../starknet-crypto", default-features = false, features = ["alloc"] } +starknet-crypto = { version = "0.7.3", path = "../starknet-crypto", default-features = false, features = ["alloc"] } starknet-core-derive = { version = "0.1.0", path = "../starknet-core-derive" } base64 = { version = "0.21.0", default-features = false, features = ["alloc"] } crypto-bigint = { version = "0.5.1", default-features = false } diff --git a/starknet-crypto/Cargo.toml b/starknet-crypto/Cargo.toml index 23c46487..44592e7c 100644 --- a/starknet-crypto/Cargo.toml +++ b/starknet-crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-crypto" -version = "0.7.2" +version = "0.7.3" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" diff --git a/starknet-signers/Cargo.toml b/starknet-signers/Cargo.toml index 436c9d99..1c040d9c 100644 --- a/starknet-signers/Cargo.toml +++ b/starknet-signers/Cargo.toml @@ -14,7 +14,7 @@ keywords = ["ethereum", "starknet", "web3"] [dependencies] starknet-core = { version = "0.12.0", path = "../starknet-core" } -starknet-crypto = { version = "0.7.2", path = "../starknet-crypto" } +starknet-crypto = { version = "0.7.3", path = "../starknet-crypto" } async-trait = "0.1.68" auto_impl = "1.0.1" thiserror = "1.0.40" From a09d4d4b68abf75172719c137fddf500bb1e3386 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 2 Dec 2024 03:28:00 +0800 Subject: [PATCH 52/54] feat: `.events()` helper on `TransactionReceipt` (#679) --- examples/starknet-wasm/src/lib.rs | 1 + starknet-core/src/types/mod.rs | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/examples/starknet-wasm/src/lib.rs b/examples/starknet-wasm/src/lib.rs index a32699fa..b4ba8248 100644 --- a/examples/starknet-wasm/src/lib.rs +++ b/examples/starknet-wasm/src/lib.rs @@ -1,4 +1,5 @@ #![allow(clippy::unused_unit)] +#![allow(unexpected_cfgs)] use starknet_crypto::Felt; use wasm_bindgen::prelude::*; diff --git a/starknet-core/src/types/mod.rs b/starknet-core/src/types/mod.rs index 174968f5..8693f7a1 100644 --- a/starknet-core/src/types/mod.rs +++ b/starknet-core/src/types/mod.rs @@ -614,6 +614,17 @@ impl TransactionReceipt { Self::DeployAccount(receipt) => &receipt.execution_result, } } + + /// Gets a reference to the transaction's emitted events. + pub fn events(&self) -> &[Event] { + match self { + Self::Invoke(receipt) => &receipt.events, + Self::L1Handler(receipt) => &receipt.events, + Self::Declare(receipt) => &receipt.events, + Self::Deploy(receipt) => &receipt.events, + Self::DeployAccount(receipt) => &receipt.events, + } + } } impl L1HandlerTransaction { From b4d90ac9c839cb7f48e9a88032a4ee50be8c85b6 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 2 Dec 2024 04:51:10 +0800 Subject: [PATCH 53/54] feat: support Argent account v0.4.0 (#680) --- examples/deploy_argent_account.rs | 11 ++++--- starknet-accounts/src/factory/argent.rs | 39 +++++++++++++++++++++---- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/examples/deploy_argent_account.rs b/examples/deploy_argent_account.rs index acd559c7..b296c645 100644 --- a/examples/deploy_argent_account.rs +++ b/examples/deploy_argent_account.rs @@ -11,8 +11,8 @@ use starknet::{ #[tokio::main] async fn main() { - // Latest hash as of 2023-09-15. For demo only. - let class_hash = felt!("0x01a736d6ed154502257f02b1ccdf4d9d1089f80811cd6acad48e6b6a9d1f2003"); + // Latest hash as of 2024-12-01. For demo only. + let class_hash = felt!("0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f"); // Anything you like here as salt let salt = felt!("12345678"); @@ -25,10 +25,9 @@ async fn main() { Felt::from_hex("YOUR_PRIVATE_KEY_IN_HEX_HERE").unwrap(), )); - let factory = - ArgentAccountFactory::new(class_hash, chain_id::SEPOLIA, Felt::ZERO, signer, provider) - .await - .unwrap(); + let factory = ArgentAccountFactory::new(class_hash, chain_id::SEPOLIA, None, signer, provider) + .await + .unwrap(); let deployment = factory.deploy_v1(salt); diff --git a/starknet-accounts/src/factory/argent.rs b/starknet-accounts/src/factory/argent.rs index 0a3b3a6c..f6677ec5 100644 --- a/starknet-accounts/src/factory/argent.rs +++ b/starknet-accounts/src/factory/argent.rs @@ -4,22 +4,41 @@ use crate::{ }; use async_trait::async_trait; -use starknet_core::types::{BlockId, BlockTag, Felt}; +use starknet_core::{ + codec::Encode, + types::{BlockId, BlockTag, Felt}, +}; use starknet_providers::Provider; use starknet_signers::{Signer, SignerInteractivityContext}; -/// [`AccountFactory`] implementation for deploying `Argent X` account contracts. +/// [`AccountFactory`] implementation for deploying `Argent X` account contracts (v0.4.0). #[derive(Debug)] pub struct ArgentAccountFactory { class_hash: Felt, chain_id: Felt, owner_public_key: Felt, - guardian_public_key: Felt, + guardian_public_key: Option, signer: S, provider: P, block_id: BlockId, } +/// Constructor parameters for Argent account v0.4.0. +#[derive(Encode)] +#[starknet(core = "starknet_core")] +struct ArgentAccountConstructorParams { + owner: ArgentSigner, + guardian: Option, +} + +/// A simplified version of `argent::signer::signer_signature::Signer` that only supports the simple +/// Starknet signer. +#[derive(Encode)] +#[starknet(core = "starknet_core")] +enum ArgentSigner { + Starknet(Felt), +} + impl ArgentAccountFactory where S: Signer, @@ -28,7 +47,7 @@ where pub async fn new( class_hash: Felt, chain_id: Felt, - guardian_public_key: Felt, + guardian_public_key: Option, signer: S, provider: P, ) -> Result { @@ -66,7 +85,17 @@ where } fn calldata(&self) -> Vec { - vec![self.owner_public_key, self.guardian_public_key] + let mut calldata = vec![]; + + // Encoding this sturct never fails + ArgentAccountConstructorParams { + owner: ArgentSigner::Starknet(self.owner_public_key), + guardian: self.guardian_public_key.map(ArgentSigner::Starknet), + } + .encode(&mut calldata) + .unwrap(); + + calldata } fn chain_id(&self) -> Felt { From 093d5ecbbd0929720db38a1ca34d516ccb807398 Mon Sep 17 00:00:00 2001 From: Jonathan LEI Date: Mon, 2 Dec 2024 09:00:34 -0700 Subject: [PATCH 54/54] fix: overly-restrictive wasm cfg for keystore (#681) --- starknet-signers/Cargo.toml | 2 +- starknet-signers/src/key_pair.rs | 6 +++--- starknet-signers/src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/starknet-signers/Cargo.toml b/starknet-signers/Cargo.toml index 1c040d9c..4192307a 100644 --- a/starknet-signers/Cargo.toml +++ b/starknet-signers/Cargo.toml @@ -24,7 +24,7 @@ coins-bip32 = { version = "0.11.1", optional = true } coins-ledger = { version = "0.12.0", default-features = false, optional = true } semver = { version = "1.0.23", optional = true } -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +[target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dependencies] eth-keystore = { version = "0.5.0", default-features = false } [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/starknet-signers/src/key_pair.rs b/starknet-signers/src/key_pair.rs index 2b24798e..e89f52da 100644 --- a/starknet-signers/src/key_pair.rs +++ b/starknet-signers/src/key_pair.rs @@ -19,7 +19,7 @@ pub struct VerifyingKey { } /// Errors using an encrypted JSON keystore. -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] #[derive(Debug, thiserror::Error)] pub enum KeystoreError { /// The file path is invalid. @@ -59,7 +59,7 @@ impl SigningKey { } /// Loads the private key from a Web3 Secret Storage Definition keystore. - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] pub fn from_keystore

(path: P, password: &str) -> Result where P: AsRef, @@ -70,7 +70,7 @@ impl SigningKey { } /// Encrypts and saves the private key to a Web3 Secret Storage Definition JSON file. - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] pub fn save_as_keystore

(&self, path: P, password: &str) -> Result<(), KeystoreError> where P: AsRef, diff --git a/starknet-signers/src/lib.rs b/starknet-signers/src/lib.rs index 14ffc9a7..ab8ec717 100644 --- a/starknet-signers/src/lib.rs +++ b/starknet-signers/src/lib.rs @@ -5,7 +5,7 @@ mod key_pair; pub use key_pair::{SigningKey, VerifyingKey}; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] pub use key_pair::KeystoreError; mod signer;