From 6bb6fa72716951e2593140b18571f5969a833e3f Mon Sep 17 00:00:00 2001 From: MikkySnow Date: Wed, 24 Jan 2024 16:06:51 +0400 Subject: [PATCH 01/13] Add crate for encryption --- Cargo.toml | 2 + ethers-encryption/.clippy.toml | 1 + ethers-encryption/.gitignore | 4 + ethers-encryption/Cargo.toml | 23 ++++ ethers-encryption/README.md | 196 ++++++++++++++++++++++++++++ ethers-encryption/release.toml | 2 + ethers-encryption/rustfmt.toml | 9 ++ ethers-encryption/src/derivation.rs | 32 +++++ ethers-encryption/src/encryption.rs | 70 ++++++++++ ethers-encryption/src/lib.rs | 130 ++++++++++++++++++ 10 files changed, 469 insertions(+) create mode 100644 ethers-encryption/.clippy.toml create mode 100644 ethers-encryption/.gitignore create mode 100644 ethers-encryption/Cargo.toml create mode 100644 ethers-encryption/README.md create mode 100644 ethers-encryption/release.toml create mode 100644 ethers-encryption/rustfmt.toml create mode 100644 ethers-encryption/src/derivation.rs create mode 100644 ethers-encryption/src/encryption.rs create mode 100644 ethers-encryption/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index c02d04f6a..919aa335d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "ethers-etherscan", "ethers-solc", "examples/ethers-wasm", + "ethers-encryption", ] default-members = [ @@ -33,6 +34,7 @@ default-members = [ "ethers-middleware", "ethers-etherscan", "ethers-solc", + "ethers-encryption", ] [package.metadata.docs.rs] diff --git a/ethers-encryption/.clippy.toml b/ethers-encryption/.clippy.toml new file mode 100644 index 000000000..6bfeada7f --- /dev/null +++ b/ethers-encryption/.clippy.toml @@ -0,0 +1 @@ +msrv = "1.62" diff --git a/ethers-encryption/.gitignore b/ethers-encryption/.gitignore new file mode 100644 index 000000000..026535e5e --- /dev/null +++ b/ethers-encryption/.gitignore @@ -0,0 +1,4 @@ +/target +.vscode +/.envrc +.idea diff --git a/ethers-encryption/Cargo.toml b/ethers-encryption/Cargo.toml new file mode 100644 index 000000000..81cd121e4 --- /dev/null +++ b/ethers-encryption/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "ethers-encryption" +version = "1.0.0" +edition = "2021" +rust-version = "1.62" +authors = ["Mike Antonuk "] +license = "MIT OR Apache-2.0" +readme = "README.md" +documentation = "https://docs.rs/ethers" +repository = "https://github.com/SigmaGmbH/ethers-rs" +homepage = "https://docs.rs/ethers" +description = "Complete Ethereum library and wallet implementation in Rust." + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +deoxys = "0.1.0" +rand = "0.8.5" +sha2 = "0.10.7" +hmac = "0.12.1" +x25519-dalek = { version = "2.0.0", features = ["static_secrets"] } \ No newline at end of file diff --git a/ethers-encryption/README.md b/ethers-encryption/README.md new file mode 100644 index 000000000..a13e15e0a --- /dev/null +++ b/ethers-encryption/README.md @@ -0,0 +1,196 @@ +#

ethers.rs

+ +**Complete Ethereum and Celo wallet implementation and utilities in Rust** + +![Github Actions](https://github.com/gakonst/ethers-rs/workflows/Tests/badge.svg) +[![Telegram Chat](https://img.shields.io/endpoint?color=neon&style=flat-square&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Fethers_rs)](https://t.me/ethers_rs) +[![Crates.io][crates-badge]][crates-url] + +[crates-badge]: https://img.shields.io/crates/v/ethers.svg +[crates-url]: https://crates.io/crates/ethers + +## Documentation + +Extensive documentation and examples are available [here](https://docs.rs/ethers). + +Alternatively, you may clone the repository and run `cd ethers/ && cargo doc --open` + +You can also run any of the examples by executing: `cargo run -p ethers --example ` + +## Add ethers-rs to your repository + +```toml +[dependencies] + +ethers = "1.0.0" +``` + + + +## Running the tests + +Tests require the following installed: + +1. [`solc`](https://solidity.readthedocs.io/en/latest/installing-solidity.html) (>=0.8.10). We also recommend using [solc-select](https://github.com/crytic/solc-select) for more flexibility. +2. [`anvil`](https://github.com/foundry-rs/foundry/blob/master/anvil/README.md) +3. [`geth`](https://github.com/ethereum/go-ethereum) + +In addition, it is recommended that you set the `ETHERSCAN_API_KEY` environment variable +for [the abigen via Etherscan](https://github.com/gakonst/ethers-rs/blob/master/ethers-contract/tests/abigen.rs) tests. +You can get one [here](https://etherscan.io/apis). + +### EVM-compatible chains support + +There are many chains live which are Ethereum JSON-RPC & EVM compatible, but do not yet have +support for [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) Typed Transactions. This means +that transactions submitted to them by default in ethers-rs will have invalid serialization. To +address that, you must use the `legacy` feature flag: + +```toml +[dependencies] + +ethers = { version = "1.0.0", features = ["legacy"] } +``` + +### Polygon support + +There is abigen support for Polygon and the Mumbai test network. It is recommended that you set the `POLYGONSCAN_API_KEY` environment variable. +You can get one [here](https://polygonscan.io/apis). + +### Avalanche support + +There is abigen support for Avalanche and the Fuji test network. It is recommended that you set the `SNOWTRACE_API_KEY` environment variable. +You can get one [here](https://snowtrace.io/apis). + +### Celo Support + +[Celo](http://celo.org/) support is turned on via the feature-flag `celo`: + +```toml +[dependencies] + +ethers = { version = "1.0.0", features = ["celo"] } +``` + +Celo's transactions differ from Ethereum transactions by including 3 new fields: + +- `fee_currency`: The currency fees are paid in (None for CELO, otherwise it's an Address) +- `gateway_fee_recipient`: The address of the fee recipient (None for no gateway fee paid) +- `gateway_fee`: Gateway fee amount (None for no gateway fee paid) + +The feature flag enables these additional fields in the transaction request builders and +in the transactions which are fetched over JSON-RPC. + +## Features + +- [x] Ethereum JSON-RPC Client +- [x] Interacting and deploying smart contracts +- [x] Type safe smart contract bindings code generation +- [x] Querying past events +- [x] Event monitoring as `Stream`s +- [x] ENS as a first class citizen +- [x] Celo support +- [x] Polygon support +- [x] Avalanche support +- [x] Websockets / `eth_subscribe` +- [x] Hardware Wallet Support +- [x] Parity APIs (`tracing`, `parity_blockWithReceipts`) +- [x] Geth TxPool API +- [ ] WASM Bindings (see note) +- [ ] FFI Bindings (see note) +- [ ] CLI for common operations + +### Websockets + +Websockets support is turned on via the feature-flag `ws`: + +```toml +[dependencies] + +ethers = { version = "1.0.0", features = ["ws"] } +``` + +### Interprocess Communication (IPC) + +IPC support is turned on via the feature-flag `ipc`: + +```toml +[dependencies] + +ethers = { version = "1.0.0", features = ["ipc"] } +``` + +### HTTP Secure (HTTPS) + +If you are looking to connect to a HTTPS endpoint, then you need to enable the `rustls` or `openssl` feature. +feature-flags. + +To enable `rustls`: + +```toml +[dependencies] + +ethers = { version = "1.0.0", features = ["rustls"] } +``` + +To enable `openssl`: + +```toml +[dependencies] + +ethers = { version = "1.0.0", features = ["openssl"] } +``` + +## Note on WASM and FFI bindings + +You should be able to build a wasm app that uses ethers-rs (see the [example](./examples/ethers-wasm) for reference). If ethers fails to +compile in WASM, please +[open an issue](https://github.com/gakonst/ethers-rs/issues/new/choose). +There is currently no plan to provide an official JS/TS-accessible library +interface. we believe [ethers.js](https://docs.ethers.io/v5/) serves that need +very well. + +Similarly, you should be able to build FFI bindings to ethers-rs. If ethers +fails to compile in c lib formats, please +[open an issue](https://github.com/gakonst/ethers-rs/issues/new/choose). +There is currently no plan to provide official FFI bindings, and as ethers-rs is +not yet stable 1.0.0, its interface may change significantly between versions. + +## Getting Help + +First, see if the answer to your question can be found in the [API documentation](https://docs.rs/ethers). If the answer +is not there, try opening an [issue](https://github.com/gakonst/ethers-rs/issues/new) with the question. + +Join the [ethers-rs telegram](https://t.me/ethers_rs) to chat with the community! + +## Contributing + +Thanks for your help improving the project! We are so happy to have you! We have +[a contributing guide](https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md) to +help you get involved in the ethers-rs project. + +If you make a Pull Request, do not forget to add your changes in the [CHANGELOG](CHANGELOG.md) and ensure your code is +properly formatted with `cargo +nightly fmt` and clippy is happy `cargo clippy`, you can even try to let clippy fix simple +issues itself: `cargo +nightly clippy --fix -Z unstable-options` + +## Related Projects + +This library would not have been possible without the great work done in: + +- [`ethers.js`](https://github.com/ethers-io/ethers.js/) +- [`rust-web3`](https://github.com/tomusdrw/rust-web3/) +- [`ethcontract-rs`](https://github.com/gnosis/ethcontract-rs/) +- [`guac_rs`](https://github.com/althea-net/guac_rs/tree/master/web3/src/jsonrpc) + +A lot of the code was inspired and adapted from them, to a unified and opinionated interface, +built with async/await and std futures from the ground up. + +## Projects using ethers-rs + +- [Yield Liquidator](https://github.com/yieldprotocol/yield-liquidator/): Liquidator for Yield Protocol +- [MEV Inspect](https://github.com/flashbots/mev-inspect-rs/): Miner Extractable Value inspector +- [Ethers Flashbots](https://github.com/onbjerg/ethers-flashbots): Ethers middleware for [Flashbots](https://docs.flashbots.net) +- [Ethers Fireblocks](https://github.com/gakonst/ethers-fireblocks): Ethers middleware and signer for [Fireblocks](https://fireblocks.io)' API +- [Celo Threshold BLS DKG](https://github.com/celo-org/celo-threshold-bls-rs/): CLI for using Celo as a data availability network for the Joint-Feldman BLS DKG +- [Celo Plumo Prover](https://github.com/celo-org/plumo-prover): Creates Celo's ultralight client proof from on-chain data +- [Celo SNARK Setup Coordinator](https://github.com/celo-org/snark-setup-operator): Coordinator for executing a pipelined Groth16 SNARK setup diff --git a/ethers-encryption/release.toml b/ethers-encryption/release.toml new file mode 100644 index 000000000..d55f4e95d --- /dev/null +++ b/ethers-encryption/release.toml @@ -0,0 +1,2 @@ +consolidate-commits = false +consolidate-pushes = true diff --git a/ethers-encryption/rustfmt.toml b/ethers-encryption/rustfmt.toml new file mode 100644 index 000000000..e70aee8cc --- /dev/null +++ b/ethers-encryption/rustfmt.toml @@ -0,0 +1,9 @@ +reorder_imports = true +imports_granularity = "Crate" +use_small_heuristics = "Max" +comment_width = 100 +wrap_comments = true +binop_separator = "Back" +trailing_comma = "Vertical" +trailing_semicolon = false +use_field_init_shorthand = true diff --git a/ethers-encryption/src/derivation.rs b/ethers-encryption/src/derivation.rs new file mode 100644 index 000000000..6d2caa720 --- /dev/null +++ b/ethers-encryption/src/derivation.rs @@ -0,0 +1,32 @@ +use deoxys::aead::{Aead, KeyInit, Payload}; +use sha2::Sha256; +use hmac::{Hmac, Mac}; + +use crate::encryption::{KEY_SIZE}; + +type HmacSha256 = Hmac; + +/// Converts provided x25519 private key to public key +pub fn x25519_private_to_public(private_key: [u8; KEY_SIZE]) -> [u8; 32] { + let secret = x25519_dalek::StaticSecret::from(private_key); + let public_key = x25519_dalek::PublicKey::from(&secret); + public_key.to_bytes() +} + +/// Performs Diffie-Hellman derivation of encryption key for transaction encryption +/// * public_key – User public key +/// Returns shared secret which can be used for derivation of encryption key +pub fn derive_shared_secret(private_key: [u8; KEY_SIZE], public_key: [u8; KEY_SIZE]) -> x25519_dalek::SharedSecret { + let secret = x25519_dalek::StaticSecret::from(private_key); + secret.diffie_hellman(&x25519_dalek::PublicKey::from(public_key)) +} + +/// Derives encryption key using KDF +pub fn derive_encryption_key(private_key: &[u8], salt: &[u8]) -> [u8; KEY_SIZE] { + let mut kdf = ::new_from_slice(salt).unwrap(); + kdf.update(private_key); + let mut derived_key = [0u8; KEY_SIZE]; + let digest = kdf.finalize(); + derived_key.copy_from_slice(&digest.into_bytes()[..KEY_SIZE]); + derived_key +} diff --git a/ethers-encryption/src/encryption.rs b/ethers-encryption/src/encryption.rs new file mode 100644 index 000000000..7fd6d393a --- /dev/null +++ b/ethers-encryption/src/encryption.rs @@ -0,0 +1,70 @@ +use sha2::Sha256; +use hmac::{Hmac, Mac}; +use rand::{rngs::OsRng, RngCore}; +use deoxys::aead::generic_array::GenericArray; +use deoxys::aead::{Aead, KeyInit, Payload}; +use deoxys::DeoxysII256; + +use crate::encryption::{KEY_SIZE, TX_KEY_PREFIX, NONCE_SIZE, TAG_SIZE }; + +use crate::encryption::derivation::{ + derive_shared_secret, + derive_encryption_key, + x25519_private_to_public +}; + +pub fn encrypt_ecdh(private_key: [u8; 32], node_public_key: [u8; 32], data: &[u8]) -> Result, deoxys::Error> { + let shared_secret = derive_shared_secret(private_key, node_public_key); + let salt = TX_KEY_PREFIX.as_bytes(); + let encryption_key = derive_encryption_key(shared_secret.as_bytes(), salt); + + // Append encryption public key + let encrypted_data = deoxys_encrypt(&encryption_key, data)?; + let public_key = x25519_private_to_public(private_key); + let mut result = Vec::::new(); + result.extend_from_slice(&public_key); + result.extend(encrypted_data); + + Ok(result) +} + +pub fn decrypt_ecdh(private_key: [u8; 32], node_public_key: [u8; 32], encrypted_data: &[u8]) -> Result, deoxys::Error> { + let shared_secret = derive_shared_secret(private_key, node_public_key); + let salt = TX_KEY_PREFIX.as_bytes(); + let encryption_key = derive_encryption_key(shared_secret.as_bytes(), salt); + deoxys_decrypt(&encryption_key, encrypted_data) +} + +pub fn deoxys_encrypt(private_key: &[u8; KEY_SIZE], data: &[u8]) -> Result, deoxys::Error> { + let mut rng = OsRng; + let mut aad = [0u8; TAG_SIZE]; + rng.fill_bytes(&mut aad); + let mut nonce = [0u8; NONCE_SIZE]; + rng.fill_bytes(&mut nonce); + let nonce = GenericArray::from_slice(&nonce); + let payload = Payload { + msg: data, + aad: &aad, + }; + let key = GenericArray::from_slice(private_key); + let encrypted = DeoxysII256::new(key).encrypt(nonce, payload); + match encrypted { + Ok(ciphertext) => { + let encrypted_data = [&nonce, aad.as_slice(), ciphertext.as_slice()].concat(); + Ok(encrypted_data) + } + Err(e) => Err(e) + } +} + +pub fn deoxys_decrypt(private_key: &[u8; KEY_SIZE], encrypted_data: &[u8]) -> Result, deoxys::Error> { + let nonce = &encrypted_data[0..NONCE_SIZE]; + let aad = &encrypted_data[NONCE_SIZE..NONCE_SIZE+TAG_SIZE]; + let ciphertext = &encrypted_data[NONCE_SIZE+TAG_SIZE..]; + let payload = Payload { + msg: ciphertext, + aad: aad, + }; + let key = GenericArray::from_slice(private_key); + DeoxysII256::new(key).decrypt( GenericArray::from_slice(nonce), payload) +} diff --git a/ethers-encryption/src/lib.rs b/ethers-encryption/src/lib.rs new file mode 100644 index 000000000..1aca73d1c --- /dev/null +++ b/ethers-encryption/src/lib.rs @@ -0,0 +1,130 @@ +use serde_json::json; +use reqwest::{Client, Url}; +use serde::{Deserialize, Serialize}; +use rand::{rngs::OsRng, RngCore}; +use std::convert::TryInto; + +pub mod derivation; +pub mod encryption; + +pub const TX_KEY_PREFIX: &str = "IOEncryptionKeyV1"; +pub const USER_KEY_PREFIX: &str = "UserEncryptionKeyV1"; +pub const TAG_SIZE: usize = 16; +pub const NONCE_SIZE: usize = 15; +pub const KEY_SIZE: usize = 32; + +#[derive(Debug, Deserialize)] +struct NodePublicKeyResponse { + result: String, +} + +pub async fn encrypt_data( + node_url: &str, + data: &[u8], +) -> Option<(Vec, [u8; 32])> { + // Get node public key + let node_public_key = match get_node_public_key(node_url).await { + Some(pk) => pk, + None => { + return None; + } + }; + + // Generate random encryption key + let mut rng = OsRng; + let mut key_material = [0u8; KEY_SIZE]; + rng.fill_bytes(&mut key_material); + + // Derive encryption key + let encryption_key = derivation::derive_encryption_key( + &key_material, + USER_KEY_PREFIX.as_bytes() + ); + + // Encrypt data + let encrypted = encryption::encrypt_ecdh( + encryption_key.clone(), + node_public_key, + data + ); + + match encrypted { + Ok(res) => Some((res.to_vec(), encryption_key)), + Err(err) => { + println!("Cannot encrypt transaction data. Reason: {:?}", err); + None + } + } +} + +pub async fn decrypt_data(node_url: &str, encryption_key: [u8; 32], data: &[u8]) -> Option> { + let node_public_key = match get_node_public_key(node_url).await { + Some(pk) => pk, + None => { + return None; + } + }; + + // Decrypt data + let decrypted = encryption::decrypt_ecdh( + encryption_key, + node_public_key, + data + ); + + match decrypted { + Ok(res) => Some(res.to_vec()), + Err(err) => { + println!("Cannot decrypt node response. Reason: {:?}", err); + None + } + } +} + +pub async fn get_node_public_key(url: &str) -> Option<[u8; 32]> { + let url = match Url::parse(url) { + Ok(url) => url, + Err(err) => { + println!("Cannot obtain node public key. Reason: {:?}", err); + return None; + } + }; + + let body = serde_json::json!({ + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getNodePublicKey", + "params": ["latest"], + }); + + let client = Client::new(); + let response = client.post(url).json(&body).send().await.ok()?; + + if !response.status().is_success() { + println!("Request failed with status: {}", response.status()); + return None; + } + + let api_response: NodePublicKeyResponse = response.json().await.ok()?; + let result_str = api_response.result.trim_start_matches("0x"); + + let res = match hex::decode(result_str) { + Ok(res) => res, + Err(err) => { + println!("Cannot obtain node public key. Reason: {:?}", err); + return None; + } + }; + + Some(convert_to_fixed_size_array(res)) +} + +fn convert_to_fixed_size_array(data: Vec) -> [u8; 32] { + let mut fixed_array = [0u8; 32]; + fixed_array.copy_from_slice(&data[..32]); + fixed_array +} + +fn bytearray_to_const_size(v: Vec) -> Option<[T; N]> { + v.try_into().ok() +} \ No newline at end of file From b3824b716c3b3c3da7db3ce93b80da74eed0a21c Mon Sep 17 00:00:00 2001 From: MikkySnow Date: Wed, 24 Jan 2024 16:08:11 +0400 Subject: [PATCH 02/13] add config.toml for git --- .cargo/config.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 000000000..c91c3f38b --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[net] +git-fetch-with-cli = true From d30d4f96f8f85bc76d1e959e0a376dc1ac336104 Mon Sep 17 00:00:00 2001 From: MikkySnow Date: Wed, 24 Jan 2024 16:21:01 +0400 Subject: [PATCH 03/13] add docs + small refactor --- ethers-encryption/src/derivation.rs | 4 +-- ethers-encryption/src/encryption.rs | 31 ++++++++++++++------- ethers-encryption/src/lib.rs | 43 +++++++++++++++++++++++------ 3 files changed, 57 insertions(+), 21 deletions(-) diff --git a/ethers-encryption/src/derivation.rs b/ethers-encryption/src/derivation.rs index 6d2caa720..5996332f5 100644 --- a/ethers-encryption/src/derivation.rs +++ b/ethers-encryption/src/derivation.rs @@ -2,12 +2,12 @@ use deoxys::aead::{Aead, KeyInit, Payload}; use sha2::Sha256; use hmac::{Hmac, Mac}; -use crate::encryption::{KEY_SIZE}; +use crate::encryption::KEY_SIZE; type HmacSha256 = Hmac; /// Converts provided x25519 private key to public key -pub fn x25519_private_to_public(private_key: [u8; KEY_SIZE]) -> [u8; 32] { +pub fn x25519_private_to_public(private_key: [u8; KEY_SIZE]) -> [u8; KEY_SIZE] { let secret = x25519_dalek::StaticSecret::from(private_key); let public_key = x25519_dalek::PublicKey::from(&secret); public_key.to_bytes() diff --git a/ethers-encryption/src/encryption.rs b/ethers-encryption/src/encryption.rs index 7fd6d393a..ab609aa9b 100644 --- a/ethers-encryption/src/encryption.rs +++ b/ethers-encryption/src/encryption.rs @@ -8,12 +8,16 @@ use deoxys::DeoxysII256; use crate::encryption::{KEY_SIZE, TX_KEY_PREFIX, NONCE_SIZE, TAG_SIZE }; use crate::encryption::derivation::{ - derive_shared_secret, - derive_encryption_key, + derive_shared_secret, + derive_encryption_key, x25519_private_to_public }; -pub fn encrypt_ecdh(private_key: [u8; 32], node_public_key: [u8; 32], data: &[u8]) -> Result, deoxys::Error> { +pub fn encrypt_ecdh( + private_key: [u8; KEY_SIZE], + node_public_key: [u8; KEY_SIZE], + data: &[u8], +) -> Result, deoxys::Error> { let shared_secret = derive_shared_secret(private_key, node_public_key); let salt = TX_KEY_PREFIX.as_bytes(); let encryption_key = derive_encryption_key(shared_secret.as_bytes(), salt); @@ -28,14 +32,21 @@ pub fn encrypt_ecdh(private_key: [u8; 32], node_public_key: [u8; 32], data: &[u8 Ok(result) } -pub fn decrypt_ecdh(private_key: [u8; 32], node_public_key: [u8; 32], encrypted_data: &[u8]) -> Result, deoxys::Error> { +pub fn decrypt_ecdh( + private_key: [u8; KEY_SIZE], + node_public_key: [u8; KEY_SIZE], + encrypted_data: &[u8], +) -> Result, deoxys::Error> { let shared_secret = derive_shared_secret(private_key, node_public_key); let salt = TX_KEY_PREFIX.as_bytes(); let encryption_key = derive_encryption_key(shared_secret.as_bytes(), salt); deoxys_decrypt(&encryption_key, encrypted_data) } -pub fn deoxys_encrypt(private_key: &[u8; KEY_SIZE], data: &[u8]) -> Result, deoxys::Error> { +pub fn deoxys_encrypt( + private_key: &[u8; KEY_SIZE], + data: &[u8], +) -> Result, deoxys::Error> { let mut rng = OsRng; let mut aad = [0u8; TAG_SIZE]; rng.fill_bytes(&mut aad); @@ -57,14 +68,14 @@ pub fn deoxys_encrypt(private_key: &[u8; KEY_SIZE], data: &[u8]) -> Result Result, deoxys::Error> { +pub fn deoxys_decrypt( + private_key: &[u8; KEY_SIZE], + encrypted_data: &[u8], +) -> Result, deoxys::Error> { let nonce = &encrypted_data[0..NONCE_SIZE]; let aad = &encrypted_data[NONCE_SIZE..NONCE_SIZE+TAG_SIZE]; let ciphertext = &encrypted_data[NONCE_SIZE+TAG_SIZE..]; - let payload = Payload { - msg: ciphertext, - aad: aad, - }; + let payload = Payload { msg: ciphertext, aad }; let key = GenericArray::from_slice(private_key); DeoxysII256::new(key).decrypt( GenericArray::from_slice(nonce), payload) } diff --git a/ethers-encryption/src/lib.rs b/ethers-encryption/src/lib.rs index 1aca73d1c..2fd61bd26 100644 --- a/ethers-encryption/src/lib.rs +++ b/ethers-encryption/src/lib.rs @@ -4,13 +4,18 @@ use serde::{Deserialize, Serialize}; use rand::{rngs::OsRng, RngCore}; use std::convert::TryInto; -pub mod derivation; -pub mod encryption; +pub use derivation; +pub use encryption; +/// Salt for derivation of transaction encryption key pub const TX_KEY_PREFIX: &str = "IOEncryptionKeyV1"; +/// Salt for derivation of user key material pub const USER_KEY_PREFIX: &str = "UserEncryptionKeyV1"; +/// Size of `tag` for DEOXYS-II encryption pub const TAG_SIZE: usize = 16; +/// Size of `nonce` for DEOXYS-II encryption pub const NONCE_SIZE: usize = 15; +/// Default size of private / public key pub const KEY_SIZE: usize = 32; #[derive(Debug, Deserialize)] @@ -18,10 +23,17 @@ struct NodePublicKeyResponse { result: String, } +/// Encrypts provided transaction or call data field +/// +/// * node_url - URL of JSON-RPC to obtain node public key +/// * data – raw data to encrypt +/// +/// Returns Some(encrypted_data, used_key) if encryption was successful, returns None in case +/// of error pub async fn encrypt_data( node_url: &str, data: &[u8], -) -> Option<(Vec, [u8; 32])> { +) -> Option<(Vec, [u8; KEY_SIZE])> { // Get node public key let node_public_key = match get_node_public_key(node_url).await { Some(pk) => pk, @@ -57,7 +69,14 @@ pub async fn encrypt_data( } } -pub async fn decrypt_data(node_url: &str, encryption_key: [u8; 32], data: &[u8]) -> Option> { +/// Decrypts provided ciphertext, received as a node response +/// +/// * node_url – URL of JSON-RPC to obtain node public key +/// * encryption_key – key, used during encryption of raw data +/// * data – ciphertext, received from node +/// +/// Returns Some(decrypted_data) in case of success, otherwise returns None +pub async fn decrypt_data(node_url: &str, encryption_key: [u8; KEY_SIZE], data: &[u8]) -> Option> { let node_public_key = match get_node_public_key(node_url).await { Some(pk) => pk, None => { @@ -81,7 +100,13 @@ pub async fn decrypt_data(node_url: &str, encryption_key: [u8; 32], data: &[u8]) } } -pub async fn get_node_public_key(url: &str) -> Option<[u8; 32]> { +/// Requests node public key, which will be used for derivation of shared +/// encryption key +/// +/// * url – URL of JSON-RPC to obtain node public key +/// +/// Returns Some(node_public_key) in case of success, otherwise returns None +pub async fn get_node_public_key(url: &str) -> Option<[u8; KEY_SIZE]> { let url = match Url::parse(url) { Ok(url) => url, Err(err) => { @@ -119,12 +144,12 @@ pub async fn get_node_public_key(url: &str) -> Option<[u8; 32]> { Some(convert_to_fixed_size_array(res)) } -fn convert_to_fixed_size_array(data: Vec) -> [u8; 32] { - let mut fixed_array = [0u8; 32]; - fixed_array.copy_from_slice(&data[..32]); +fn convert_to_fixed_size_array(data: Vec) -> [u8; KEY_SIZE] { + let mut fixed_array = [0u8; KEY_SIZE]; + fixed_array.copy_from_slice(&data[..KEY_SIZE]); fixed_array } fn bytearray_to_const_size(v: Vec) -> Option<[T; N]> { v.try_into().ok() -} \ No newline at end of file +} From 6d2f386a9c742d772b7adc34259198655b174e1e Mon Sep 17 00:00:00 2001 From: MikkySnow Date: Wed, 24 Jan 2024 16:27:27 +0400 Subject: [PATCH 04/13] fix build issues --- Cargo.lock | 235 +++++++++++++++++++--------- ethers-encryption/Cargo.toml | 6 +- ethers-encryption/src/derivation.rs | 2 +- ethers-encryption/src/encryption.rs | 4 +- ethers-encryption/src/lib.rs | 4 +- 5 files changed, 172 insertions(+), 79 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ecf6d76f..8eb4257f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,7 +101,7 @@ checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -135,7 +135,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -147,7 +147,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -260,7 +260,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" dependencies = [ - "digest 0.10.5", + "digest 0.10.7", ] [[package]] @@ -560,7 +560,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -571,7 +571,7 @@ checksum = "606383658416244b8dc4b36f864ec1f86cb922b95c41a908fd07aeb01cad06fa" dependencies = [ "cipher 0.4.3", "dbl", - "digest 0.10.5", + "digest 0.10.7", ] [[package]] @@ -583,13 +583,13 @@ dependencies = [ "bincode", "bs58", "coins-core", - "digest 0.10.5", + "digest 0.10.7", "getrandom 0.2.8", "hmac 0.12.1", "k256", "lazy_static", "serde", - "sha2 0.10.6", + "sha2 0.10.8", "thiserror", ] @@ -606,7 +606,7 @@ dependencies = [ "hmac 0.12.1", "pbkdf2 0.11.0", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.8", "thiserror", ] @@ -620,13 +620,13 @@ dependencies = [ "base64 0.12.3", "bech32", "blake2", - "digest 0.10.5", + "digest 0.10.7", "generic-array 0.14.6", "hex", "ripemd", "serde", "serde_derive", - "sha2 0.10.6", + "sha2 0.10.8", "sha3", "thiserror", ] @@ -732,9 +732,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -898,7 +898,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" dependencies = [ "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -923,6 +923,33 @@ dependencies = [ "zeroize", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "curve25519-dalek-derive", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "dashmap" version = "5.2.0" @@ -943,6 +970,18 @@ dependencies = [ "generic-array 0.14.6", ] +[[package]] +name = "deoxys" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00603a49e114bd99d87a4ab8d480f36ecd1451a9d6474f66973d1a829ff77789" +dependencies = [ + "aead", + "aes 0.8.1", + "subtle", + "zeroize", +] + [[package]] name = "der" version = "0.6.0" @@ -961,7 +1000,7 @@ checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -1002,9 +1041,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.5" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.0", "crypto-common", @@ -1065,7 +1104,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 3.2.0", "ed25519", "rand 0.7.3", "serde", @@ -1088,7 +1127,7 @@ dependencies = [ "base16ct", "crypto-bigint", "der", - "digest 0.10.5", + "digest 0.10.7", "ff", "generic-array 0.14.6", "group", @@ -1165,7 +1204,7 @@ checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" dependencies = [ "aes 0.8.1", "ctr", - "digest 0.10.5", + "digest 0.10.7", "hex", "hmac 0.12.1", "pbkdf2 0.11.0", @@ -1173,7 +1212,7 @@ dependencies = [ "scrypt", "serde", "serde_json", - "sha2 0.10.6", + "sha2 0.10.8", "sha3", "thiserror", "uuid 0.8.2", @@ -1297,7 +1336,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "syn", + "syn 1.0.103", "tempfile", "toml", "url", @@ -1314,7 +1353,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn", + "syn 1.0.103", ] [[package]] @@ -1342,7 +1381,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn", + "syn 1.0.103", "thiserror", "tiny-keccak", "unicode-xid", @@ -1357,7 +1396,22 @@ dependencies = [ "hex", "quote", "serde_json", - "syn", + "syn 1.0.103", +] + +[[package]] +name = "ethers-encryption" +version = "1.0.0" +dependencies = [ + "deoxys", + "hex", + "hmac 0.12.1", + "rand 0.8.5", + "reqwest", + "serde", + "serde_json", + "sha2 0.10.8", + "x25519-dalek", ] [[package]] @@ -1468,7 +1522,7 @@ dependencies = [ "rusoto_kms", "semver", "serde_json", - "sha2 0.10.6", + "sha2 0.10.8", "spki", "tempfile", "thiserror", @@ -1505,7 +1559,7 @@ dependencies = [ "semver", "serde", "serde_json", - "sha2 0.10.6", + "sha2 0.10.8", "solang-parser", "svm-rs", "svm-rs-builds", @@ -1571,6 +1625,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" + [[package]] name = "fixed-hash" version = "0.8.0" @@ -1717,7 +1777,7 @@ checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -1929,7 +1989,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.5", + "digest 0.10.7", ] [[package]] @@ -2076,7 +2136,7 @@ checksum = "d5dacb10c5b3bb92d46ba347505a9041e676bb20ad220101326bffb0c93031ee" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -2205,7 +2265,7 @@ dependencies = [ "cfg-if 1.0.0", "ecdsa", "elliptic-curve", - "sha2 0.10.6", + "sha2 0.10.8", "sha3", ] @@ -2255,9 +2315,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.137" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libusb1-sys" @@ -2327,7 +2387,7 @@ version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" dependencies = [ - "digest 0.10.5", + "digest 0.10.7", ] [[package]] @@ -2515,7 +2575,7 @@ dependencies = [ "bytes", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -2583,7 +2643,7 @@ checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" dependencies = [ "ecdsa", "elliptic-curve", - "sha2 0.10.6", + "sha2 0.10.8", ] [[package]] @@ -2594,7 +2654,7 @@ checksum = "70723b6e03216e79df3765a7e4cdf39746c4a2392ba4bdb458111a939494cc1d" dependencies = [ "ecdsa", "elliptic-curve", - "sha2 0.10.6", + "sha2 0.10.8", ] [[package]] @@ -2620,7 +2680,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -2705,10 +2765,10 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" dependencies = [ - "digest 0.10.5", + "digest 0.10.7", "hmac 0.12.1", "password-hash 0.3.2", - "sha2 0.10.6", + "sha2 0.10.8", ] [[package]] @@ -2717,10 +2777,10 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest 0.10.5", + "digest 0.10.7", "hmac 0.12.1", "password-hash 0.4.2", - "sha2 0.10.6", + "sha2 0.10.8", ] [[package]] @@ -2781,7 +2841,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -2825,7 +2885,7 @@ checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -2856,6 +2916,12 @@ version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" +[[package]] +name = "platforms" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" + [[package]] name = "plotters" version = "0.3.1" @@ -2941,7 +3007,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.103", "version_check", ] @@ -2964,9 +3030,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -2979,9 +3045,9 @@ checksum = "47c327e191621a2158159df97cdbc2e7074bb4e940275e35abf38eb3d2595754" [[package]] name = "quote" -version = "1.0.16" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -3220,7 +3286,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1facec54cb5e0dc08553501fa740091086d0259ad0067e0d4103448e4cb22ed3" dependencies = [ - "digest 0.10.5", + "digest 0.10.7", ] [[package]] @@ -3241,7 +3307,7 @@ checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -3438,7 +3504,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -3472,7 +3538,7 @@ dependencies = [ "hmac 0.12.1", "pbkdf2 0.11.0", "salsa20", - "sha2 0.10.6", + "sha2 0.10.8", ] [[package]] @@ -3585,7 +3651,7 @@ checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -3634,7 +3700,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -3645,7 +3711,7 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.5", + "digest 0.10.7", ] [[package]] @@ -3656,7 +3722,7 @@ checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.5", + "digest 0.10.7", ] [[package]] @@ -3687,13 +3753,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.5", + "digest 0.10.7", "sha2-asm", ] @@ -3712,7 +3778,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31f935e31cf406e8c0e96c2815a5516181b7004ae8c5f296293221e9b1e356bd" dependencies = [ - "digest 0.10.5", + "digest 0.10.7", "keccak", ] @@ -3746,7 +3812,7 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb766570a2825fa972bceff0d195727876a9cdf2460ab2e52d455dc2de47fd9" dependencies = [ - "digest 0.10.5", + "digest 0.10.7", "rand_core 0.6.3", "signature_derive", ] @@ -3759,7 +3825,7 @@ checksum = "96e6310f022b5c02b3bba689166e833f6b96994a6ce1f138b653d2fd0519920f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -3863,7 +3929,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn", + "syn 1.0.103", ] [[package]] @@ -3927,6 +3993,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -3935,7 +4012,7 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", "unicode-xid", ] @@ -4021,7 +4098,7 @@ checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -4114,7 +4191,7 @@ checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -4205,7 +4282,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", ] [[package]] @@ -4479,7 +4556,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.103", "wasm-bindgen-shared", ] @@ -4513,7 +4590,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4771,6 +4848,18 @@ dependencies = [ "tap", ] +[[package]] +name = "x25519-dalek" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" +dependencies = [ + "curve25519-dalek 4.1.1", + "rand_core 0.6.3", + "serde", + "zeroize", +] + [[package]] name = "xml-rs" version = "0.8.4" @@ -4794,7 +4883,7 @@ dependencies = [ "cbc", "ccm", "cmac", - "digest 0.10.5", + "digest 0.10.7", "ecdsa", "ed25519", "ed25519-dalek", @@ -4808,7 +4897,7 @@ dependencies = [ "rusb", "serde", "serde_json", - "sha2 0.10.6", + "sha2 0.10.8", "signature", "subtle", "thiserror", @@ -4834,7 +4923,7 @@ checksum = "81e8f13fef10b63c06356d65d416b070798ddabcadc10d3ece0c5be9b3c7eddb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.103", "synstructure", ] diff --git a/ethers-encryption/Cargo.toml b/ethers-encryption/Cargo.toml index 81cd121e4..6c5a99101 100644 --- a/ethers-encryption/Cargo.toml +++ b/ethers-encryption/Cargo.toml @@ -20,4 +20,8 @@ deoxys = "0.1.0" rand = "0.8.5" sha2 = "0.10.7" hmac = "0.12.1" -x25519-dalek = { version = "2.0.0", features = ["static_secrets"] } \ No newline at end of file +x25519-dalek = { version = "2.0.0", features = ["static_secrets"] } +hex = { version = "0.4.3", default-features = false, features = ["std"] } +reqwest = { version = "0.11.13", default-features = false, features = ["json"] } +serde = { version = "1.0.124", default-features = false, features = ["derive"] } +serde_json = { version = "1.0.64", default-features = false, features = ["raw_value"] } diff --git a/ethers-encryption/src/derivation.rs b/ethers-encryption/src/derivation.rs index 5996332f5..7a6027bc7 100644 --- a/ethers-encryption/src/derivation.rs +++ b/ethers-encryption/src/derivation.rs @@ -2,7 +2,7 @@ use deoxys::aead::{Aead, KeyInit, Payload}; use sha2::Sha256; use hmac::{Hmac, Mac}; -use crate::encryption::KEY_SIZE; +use crate::KEY_SIZE; type HmacSha256 = Hmac; diff --git a/ethers-encryption/src/encryption.rs b/ethers-encryption/src/encryption.rs index ab609aa9b..0a1e6087b 100644 --- a/ethers-encryption/src/encryption.rs +++ b/ethers-encryption/src/encryption.rs @@ -5,9 +5,9 @@ use deoxys::aead::generic_array::GenericArray; use deoxys::aead::{Aead, KeyInit, Payload}; use deoxys::DeoxysII256; -use crate::encryption::{KEY_SIZE, TX_KEY_PREFIX, NONCE_SIZE, TAG_SIZE }; +use crate::{KEY_SIZE, TX_KEY_PREFIX, NONCE_SIZE, TAG_SIZE }; -use crate::encryption::derivation::{ +use crate::derivation::{ derive_shared_secret, derive_encryption_key, x25519_private_to_public diff --git a/ethers-encryption/src/lib.rs b/ethers-encryption/src/lib.rs index 2fd61bd26..24515a1cc 100644 --- a/ethers-encryption/src/lib.rs +++ b/ethers-encryption/src/lib.rs @@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize}; use rand::{rngs::OsRng, RngCore}; use std::convert::TryInto; -pub use derivation; -pub use encryption; +pub mod derivation; +pub mod encryption; /// Salt for derivation of transaction encryption key pub const TX_KEY_PREFIX: &str = "IOEncryptionKeyV1"; From 0c2d5efdf3f5e49ee47aa72688a75b39a73ad7da Mon Sep 17 00:00:00 2001 From: MikkySnow Date: Wed, 24 Jan 2024 16:54:47 +0400 Subject: [PATCH 05/13] add basic encryption in eth_call and eth_estimateGas --- Cargo.lock | 1 + ethers-providers/Cargo.toml | 1 + ethers-providers/src/provider.rs | 62 ++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 8eb4257f9..bb708698b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1472,6 +1472,7 @@ dependencies = [ "base64 0.13.1", "bytes", "ethers-core", + "ethers-encryption", "futures-channel", "futures-core", "futures-timer", diff --git a/ethers-providers/Cargo.toml b/ethers-providers/Cargo.toml index 9e4829234..a49da8d29 100644 --- a/ethers-providers/Cargo.toml +++ b/ethers-providers/Cargo.toml @@ -16,6 +16,7 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] ethers-core = { version = "^1.0.0", path = "../ethers-core", default-features = false } +ethers-encryption = { version = "^1.0.0", path = "../ethers-encryption", default-features = false } async-trait = { version = "0.1.50", default-features = false } hex = { version = "0.4.3", default-features = false, features = ["std"] } diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs index ff4eb8b31..b3d0326f1 100644 --- a/ethers-providers/src/provider.rs +++ b/ethers-providers/src/provider.rs @@ -569,6 +569,44 @@ impl Middleware for Provider

{ tx: &TypedTransaction, block: Option, ) -> Result { + let chain_id = self.get_chainid().await?; + if chain_id.as_u32() == 1291 && tx.data().is_some() && tx.to().is_some() { + // Obtain node public key and encrypt tx.data + let node_url = "https://json-rpc.testnet.swisstronik.com"; + let (encrypted_data, _) = ethers_encryption::encrypt_data(node_url, tx.data().unwrap()) + .await + .ok_or_else(|| ProviderError::CustomError(String::from("Cannot encrypt transaction data")))?; + + // Update tx.data field + let mut encrypted_tx = tx.clone(); + let encrypted_tx = encrypted_tx.set_data(encrypted_data.into()); + + let tx = utils::serialize(encrypted_tx); + let block = utils::serialize(&block.unwrap_or_else(|| BlockNumber::Latest.into())); + let response: Result = self.request("eth_call", [tx, block]).await; + + match response { + Ok(result) => { + let decrypted_data = ethers_encryption::decrypt_data( + node_url, + encryption_key, + &result, + ).await; + match decrypted_data { + Some(data) => { + return Ok(data.into()); + }, + None => { + return Err(ProviderError::CustomError("Cannot decrypt node response".to_string())); + } + } + }, + _ => {}, + } + + return response + } + let tx = utils::serialize(tx); let block = utils::serialize(&block.unwrap_or_else(|| BlockNumber::Latest.into())); self.request("eth_call", [tx, block]).await @@ -583,6 +621,30 @@ impl Middleware for Provider

{ tx: &TypedTransaction, block: Option, ) -> Result { + let chain_id = self.get_chainid().await?; + if chain_id.as_u32() == 1291 && tx.data().is_some() && tx.to().is_some() { + // Obtain node public key and encrypt tx.data + let node_url = "https://json-rpc.testnet.swisstronik.com"; + let (encrypted_data, _) = ethers_encryption::encrypt_data(node_url, tx.data().unwrap()) + .await + .ok_or_else(|| ProviderError::CustomError(String::from("Cannot encrypt transaction data")))?; + + // Update tx.data field + let mut encrypted_tx = tx.clone(); + let encrypted_tx = encrypted_tx.set_data(encrypted_data.into()); + + let tx = utils::serialize(encrypted_tx); + let block = utils::serialize(&block.unwrap_or_else(|| BlockNumber::Latest.into())); + // Some nodes (e.g. old Optimism clients) don't support a block ID being passed as a param, + // so refrain from defaulting to BlockNumber::Latest. + let params = if let Some(block_id) = block { + vec![tx, utils::serialize(&block_id)] + } else { + vec![tx] + }; + return self.request("eth_estimateGas", params).await + } + let tx = utils::serialize(tx); // Some nodes (e.g. old Optimism clients) don't support a block ID being passed as a param, // so refrain from defaulting to BlockNumber::Latest. From 0ea8da8d63b00b1f64b2410b631570fddb8f3094 Mon Sep 17 00:00:00 2001 From: MikkySnow Date: Wed, 24 Jan 2024 17:15:43 +0400 Subject: [PATCH 06/13] obtain node url from provider connecton --- ethers-providers/src/lib.rs | 3 +++ ethers-providers/src/provider.rs | 23 ++++++++++++----------- ethers-providers/src/transports/http.rs | 4 ++++ ethers-providers/src/transports/ipc.rs | 4 ++++ ethers-providers/src/transports/mock.rs | 4 ++++ ethers-providers/src/transports/quorum.rs | 4 ++++ ethers-providers/src/transports/retry.rs | 6 +++++- ethers-providers/src/transports/rw.rs | 4 ++++ ethers-providers/src/transports/ws.rs | 4 ++++ 9 files changed, 44 insertions(+), 12 deletions(-) diff --git a/ethers-providers/src/lib.rs b/ethers-providers/src/lib.rs index 6905b14af..d28ffe907 100644 --- a/ethers-providers/src/lib.rs +++ b/ethers-providers/src/lib.rs @@ -69,6 +69,9 @@ pub trait JsonRpcClient: Debug + Send + Sync { where T: Debug + Serialize + Send + Sync, R: DeserializeOwned; + + /// Returns URL of connected node + fn connection(&self) -> String; } use ethers_core::types::*; diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs index b3d0326f1..40388b76b 100644 --- a/ethers-providers/src/provider.rs +++ b/ethers-providers/src/provider.rs @@ -572,10 +572,12 @@ impl Middleware for Provider

{ let chain_id = self.get_chainid().await?; if chain_id.as_u32() == 1291 && tx.data().is_some() && tx.to().is_some() { // Obtain node public key and encrypt tx.data - let node_url = "https://json-rpc.testnet.swisstronik.com"; - let (encrypted_data, _) = ethers_encryption::encrypt_data(node_url, tx.data().unwrap()) - .await - .ok_or_else(|| ProviderError::CustomError(String::from("Cannot encrypt transaction data")))?; + let node_url = self.inner.connection(); + + let (encrypted_data, encryption_key) = ethers_encryption::encrypt_data( + node_url.as_str(), + tx.data().unwrap() + ).await.ok_or_else(|| ProviderError::CustomError(String::from("Cannot encrypt transaction data")))?; // Update tx.data field let mut encrypted_tx = tx.clone(); @@ -588,16 +590,16 @@ impl Middleware for Provider

{ match response { Ok(result) => { let decrypted_data = ethers_encryption::decrypt_data( - node_url, + node_url.as_str(), encryption_key, &result, ).await; - match decrypted_data { + return match decrypted_data { Some(data) => { - return Ok(data.into()); + Ok(data.into()) }, None => { - return Err(ProviderError::CustomError("Cannot decrypt node response".to_string())); + Err(ProviderError::CustomError("Cannot decrypt node response".to_string())) } } }, @@ -624,8 +626,8 @@ impl Middleware for Provider

{ let chain_id = self.get_chainid().await?; if chain_id.as_u32() == 1291 && tx.data().is_some() && tx.to().is_some() { // Obtain node public key and encrypt tx.data - let node_url = "https://json-rpc.testnet.swisstronik.com"; - let (encrypted_data, _) = ethers_encryption::encrypt_data(node_url, tx.data().unwrap()) + let node_url = self.inner.connection(); + let (encrypted_data, _) = ethers_encryption::encrypt_data(node_url.as_str(), tx.data().unwrap()) .await .ok_or_else(|| ProviderError::CustomError(String::from("Cannot encrypt transaction data")))?; @@ -634,7 +636,6 @@ impl Middleware for Provider

{ let encrypted_tx = encrypted_tx.set_data(encrypted_data.into()); let tx = utils::serialize(encrypted_tx); - let block = utils::serialize(&block.unwrap_or_else(|| BlockNumber::Latest.into())); // Some nodes (e.g. old Optimism clients) don't support a block ID being passed as a param, // so refrain from defaulting to BlockNumber::Latest. let params = if let Some(block_id) = block { diff --git a/ethers-providers/src/transports/http.rs b/ethers-providers/src/transports/http.rs index e697bb896..fa411702e 100644 --- a/ethers-providers/src/transports/http.rs +++ b/ethers-providers/src/transports/http.rs @@ -106,6 +106,10 @@ impl JsonRpcClient for Provider { Ok(res) } + + fn connection(&self) -> String { + self.url.to_string() + } } impl Provider { diff --git a/ethers-providers/src/transports/ipc.rs b/ethers-providers/src/transports/ipc.rs index acd111cf0..eb873b58d 100644 --- a/ethers-providers/src/transports/ipc.rs +++ b/ethers-providers/src/transports/ipc.rs @@ -105,6 +105,10 @@ impl JsonRpcClient for Ipc { // Parse JSON response. Ok(serde_json::from_str(res.get())?) } + + fn connection(&self) -> String { + "127.0.0.1:8545".to_string() + } } impl PubsubClient for Ipc { diff --git a/ethers-providers/src/transports/mock.rs b/ethers-providers/src/transports/mock.rs index e6ff8f5c8..b9a0a8336 100644 --- a/ethers-providers/src/transports/mock.rs +++ b/ethers-providers/src/transports/mock.rs @@ -56,6 +56,10 @@ impl JsonRpcClient for MockProvider { Ok(res) } + + fn connection(&self) -> String { + "http://127.0.0.1:8545".to_string() + } } impl MockProvider { diff --git a/ethers-providers/src/transports/quorum.rs b/ethers-providers/src/transports/quorum.rs index c564eb1fd..c43a3f2c7 100644 --- a/ethers-providers/src/transports/quorum.rs +++ b/ethers-providers/src/transports/quorum.rs @@ -588,6 +588,10 @@ where } } } + + fn connection(&self) -> String { + "127.0.0.1:8545".to_string() + } } // A stream that returns a value and the weight of its provider diff --git a/ethers-providers/src/transports/retry.rs b/ethers-providers/src/transports/retry.rs index 11b7386b6..d684e57b9 100644 --- a/ethers-providers/src/transports/retry.rs +++ b/ethers-providers/src/transports/retry.rs @@ -76,7 +76,7 @@ where /// # Example /// /// ``` - /// + /// /// # async fn demo() { /// use ethers_providers::{Http, RetryClient, HttpRateLimitRetryPolicy}; /// use std::time::Duration; @@ -335,6 +335,10 @@ where } } } + + fn connection(&self) -> String { + self.inner.connection() + } } /// Implements [RetryPolicy] that will retry requests that errored with diff --git a/ethers-providers/src/transports/rw.rs b/ethers-providers/src/transports/rw.rs index f54a96ebc..300842c5c 100644 --- a/ethers-providers/src/transports/rw.rs +++ b/ethers-providers/src/transports/rw.rs @@ -124,4 +124,8 @@ where _ => self.r.request(method, params).await.map_err(RwClientError::Read), } } + + fn connection(&self) -> String { + self.r.connection() + } } diff --git a/ethers-providers/src/transports/ws.rs b/ethers-providers/src/transports/ws.rs index d05970ec9..ebd980ede 100644 --- a/ethers-providers/src/transports/ws.rs +++ b/ethers-providers/src/transports/ws.rs @@ -187,6 +187,10 @@ impl JsonRpcClient for Ws { // parse it Ok(serde_json::from_str(res.get())?) } + + fn connection(&self) -> String { + "127.0.0.1:8545".to_string() + } } impl PubsubClient for Ws { From 746722d4394dde06ceda19f26bc09511735745b6 Mon Sep 17 00:00:00 2001 From: MikkySnow Date: Wed, 24 Jan 2024 18:55:40 +0400 Subject: [PATCH 07/13] add encryption for eth_sendTransaction --- Cargo.lock | 1 + ethers-middleware/Cargo.toml | 1 + ethers-middleware/src/gas_escalator/mod.rs | 14 ++++++++-- .../src/gas_oracle/middleware.rs | 12 +++++++- ethers-middleware/src/nonce_manager.rs | 11 +++++++- ethers-middleware/src/policy.rs | 10 +++++-- ethers-middleware/src/signer.rs | 28 +++++++++++++++---- ethers-middleware/src/timelag/mod.rs | 15 ++++++---- .../src/transformer/middleware.rs | 12 +++++++- ethers-providers/src/lib.rs | 2 ++ ethers-providers/src/provider.rs | 13 ++++----- 11 files changed, 94 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb708698b..69b72a31e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1442,6 +1442,7 @@ dependencies = [ "auto_impl 0.5.0", "ethers-contract", "ethers-core", + "ethers-encryption", "ethers-etherscan", "ethers-providers", "ethers-signers", diff --git a/ethers-middleware/Cargo.toml b/ethers-middleware/Cargo.toml index b53788bf8..355e8d372 100644 --- a/ethers-middleware/Cargo.toml +++ b/ethers-middleware/Cargo.toml @@ -20,6 +20,7 @@ ethers-core = { version = "^1.0.0", path = "../ethers-core", default-features = ethers-etherscan = { version = "^1.0.0", path = "../ethers-etherscan", default-features = false } ethers-providers = { version = "^1.0.0", path = "../ethers-providers", default-features = false } ethers-signers = { version = "^1.0.0", path = "../ethers-signers", default-features = false } +ethers-encryption = { version = "^1.0.0", path = "../ethers-encryption", default-features = false } async-trait = { version = "0.1.50", default-features = false } auto_impl = { version = "0.5.0", default-features = false } diff --git a/ethers-middleware/src/gas_escalator/mod.rs b/ethers-middleware/src/gas_escalator/mod.rs index a71adbf3e..6bbc85e46 100644 --- a/ethers-middleware/src/gas_escalator/mod.rs +++ b/ethers-middleware/src/gas_escalator/mod.rs @@ -6,15 +6,21 @@ mod linear; pub use linear::LinearGasPrice; use async_trait::async_trait; -use ethers_core::types::{BlockId, TransactionRequest, TxHash, U256}; -use ethers_providers::{interval, FromErr, Middleware, PendingTransaction, StreamExt}; +use ethers_core::types::{Address, Block, BlockId, BlockNumber, BlockTrace, Bytes, EIP1186ProofResponse, FeeHistory, Filter, GethDebugTracingOptions, GethTrace, Log, NameOrAddress, Signature, SyncingStatus, Trace, TraceFilter, TraceType, Transaction, TransactionReceipt, TransactionRequest, TxHash, TxpoolContent, TxpoolInspect, TxpoolStatus, U256, U64}; +use ethers_providers::{interval, FromErr, Middleware, PendingTransaction, StreamExt, Provider, EscalationPolicy, EscalatingPending, LogQuery, FilterKind, FilterWatcher, ProviderError, SubscriptionStream, PubsubClient}; use futures_util::lock::Mutex; use instant::Instant; use std::{pin::Pin, sync::Arc}; +use std::fmt::Debug; +use serde::de::DeserializeOwned; +use serde::Serialize; use thiserror::Error; #[cfg(not(target_arch = "wasm32"))] use tokio::spawn; +use url::Url; +use ethers_core::types::transaction::eip2930::AccessListWithGasUsed; +use ethers_providers::erc::ERCNFT; #[cfg(target_arch = "wasm32")] type WatcherFuture<'a> = Pin + 'a>>; @@ -98,6 +104,10 @@ where &self.inner } + fn connection(&self) -> String { + self.inner.connection() + } + async fn send_transaction + Send + Sync>( &self, tx: T, diff --git a/ethers-middleware/src/gas_oracle/middleware.rs b/ethers-middleware/src/gas_oracle/middleware.rs index 272b01509..84b4ddad3 100644 --- a/ethers-middleware/src/gas_oracle/middleware.rs +++ b/ethers-middleware/src/gas_oracle/middleware.rs @@ -1,8 +1,14 @@ +use std::fmt::Debug; use super::{GasOracle, GasOracleError}; use async_trait::async_trait; +use serde::de::DeserializeOwned; +use serde::Serialize; use ethers_core::types::{transaction::eip2718::TypedTransaction, *}; -use ethers_providers::{FromErr, Middleware, PendingTransaction}; +use ethers_providers::{EscalatingPending, EscalationPolicy, FilterKind, FilterWatcher, FromErr, LogQuery, Middleware, PendingTransaction, Provider, ProviderError, PubsubClient, SubscriptionStream}; use thiserror::Error; +use url::Url; +use ethers_core::types::transaction::eip2930::AccessListWithGasUsed; +use ethers_providers::erc::ERCNFT; #[derive(Debug)] /// Middleware used for fetching gas prices over an API instead of `eth_gasPrice` @@ -56,6 +62,10 @@ where &self.inner } + fn connection(&self) -> String { + self.inner.connection() + } + async fn fill_transaction( &self, tx: &mut TypedTransaction, diff --git a/ethers-middleware/src/nonce_manager.rs b/ethers-middleware/src/nonce_manager.rs index 50a5ae519..2c30d1377 100644 --- a/ethers-middleware/src/nonce_manager.rs +++ b/ethers-middleware/src/nonce_manager.rs @@ -1,11 +1,16 @@ use async_trait::async_trait; use ethers_core::types::{transaction::eip2718::TypedTransaction, *}; -use ethers_providers::{FromErr, Middleware, PendingTransaction}; +use ethers_providers::{EscalatingPending, EscalationPolicy, FilterKind, FilterWatcher, FromErr, LogQuery, Middleware, PendingTransaction, Provider, ProviderError, PubsubClient, SubscriptionStream}; use std::{ fmt::Debug, sync::atomic::{AtomicBool, AtomicU64, Ordering}, }; +use serde::de::DeserializeOwned; +use serde::Serialize; use thiserror::Error; +use url::Url; +use ethers_core::types::transaction::eip2930::AccessListWithGasUsed; +use ethers_providers::erc::ERCNFT; #[derive(Debug)] /// Middleware used for calculating nonces locally, useful for signing multiple @@ -98,6 +103,10 @@ where &self.inner } + fn connection(&self) -> String { + self.inner.connection() + } + async fn fill_transaction( &self, tx: &mut TypedTransaction, diff --git a/ethers-middleware/src/policy.rs b/ethers-middleware/src/policy.rs index fc69d52eb..d4fc9bb18 100644 --- a/ethers-middleware/src/policy.rs +++ b/ethers-middleware/src/policy.rs @@ -1,9 +1,11 @@ -use ethers_core::types::{transaction::eip2718::TypedTransaction, BlockId}; -use ethers_providers::{FromErr, Middleware, PendingTransaction}; +use ethers_core::types::{transaction::eip2718::TypedTransaction, BlockId, Address, U64, Block, H256}; +use ethers_providers::{EscalatingPending, EscalationPolicy, FromErr, Middleware, PendingTransaction, Provider}; use async_trait::async_trait; use std::fmt::Debug; use thiserror::Error; +use url::Url; +use ethers_providers::erc::ERCNFT; /// Basic trait to ensure that transactions about to be sent follow certain rules. #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] @@ -95,6 +97,10 @@ where &self.inner } + fn connection(&self) -> String { + self.inner.connection() + } + /// This ensures the tx complies with the registered policy. /// If so then this simply delegates the transaction to the inner middleware async fn send_transaction + Send + Sync>( diff --git a/ethers-middleware/src/signer.rs b/ethers-middleware/src/signer.rs index 36af4f031..8d522ad0f 100644 --- a/ethers-middleware/src/signer.rs +++ b/ethers-middleware/src/signer.rs @@ -1,13 +1,15 @@ -use ethers_core::types::{ - transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed}, - Address, BlockId, Bytes, Chain, Signature, TransactionRequest, U256, -}; -use ethers_providers::{maybe, FromErr, Middleware, PendingTransaction}; +use ethers_core::types::{transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed}, Address, BlockId, Bytes, Chain, Signature, TransactionRequest, U256, U64, Block, H256, Transaction, NameOrAddress, SyncingStatus, TransactionReceipt, BlockNumber, Filter, Log, EIP1186ProofResponse, TxpoolContent, TxpoolInspect, TxpoolStatus, GethDebugTracingOptions, GethTrace, TraceType, BlockTrace, Trace, TraceFilter, FeeHistory}; +use ethers_providers::{maybe, FromErr, Middleware, PendingTransaction, Provider, EscalationPolicy, EscalatingPending, LogQuery, FilterKind, FilterWatcher, ProviderError, SubscriptionStream, PubsubClient}; use ethers_signers::Signer; use std::convert::TryFrom; +use std::fmt::Debug; use async_trait::async_trait; +use serde::de::DeserializeOwned; +use serde::Serialize; use thiserror::Error; +use url::Url; +use ethers_providers::erc::ERCNFT; #[derive(Clone, Debug)] /// Middleware used for locally signing transactions, compatible with any implementer @@ -142,6 +144,18 @@ where _ => {} } + if chain_id == 1291 && tx.to().is_some() && tx.data().is_some() { + // Encryption transaction data in case of swisstronik network + let node_url = self.connection(); + // Encrypt call data in case of Swisstronik network + let (encrypted_data, _) = ethers_encryption::encrypt_data(node_url.as_str(), tx.data().unwrap()) + .await + .expect("Cannot encrypt transaction"); + + // Update call data + tx.set_data(encrypted_data.into()); + } + let signature = self.signer.sign_transaction(&tx).await.map_err(SignerMiddlewareError::SignerError)?; @@ -214,6 +228,10 @@ where &self.inner } + fn connection(&self) -> String { + self.inner.connection() + } + /// Returns the client's address fn default_sender(&self) -> Option

{ Some(self.address) diff --git a/ethers-middleware/src/timelag/mod.rs b/ethers-middleware/src/timelag/mod.rs index 6c1e90b81..27dcdbf82 100644 --- a/ethers-middleware/src/timelag/mod.rs +++ b/ethers-middleware/src/timelag/mod.rs @@ -1,12 +1,13 @@ use async_trait::async_trait; -use ethers_core::types::{ - transaction::eip2718::TypedTransaction, Block, BlockId, BlockNumber, Bytes, FilterBlockOption, - NameOrAddress, Transaction, TransactionReceipt, TxHash, U256, -}; +use ethers_core::types::{transaction::eip2718::TypedTransaction, Block, BlockId, BlockNumber, Bytes, FilterBlockOption, NameOrAddress, Transaction, TransactionReceipt, TxHash, U256, Address, SyncingStatus, Signature, Filter, Log, EIP1186ProofResponse, TxpoolContent, TxpoolInspect, TxpoolStatus, GethDebugTracingOptions, GethTrace, TraceType, BlockTrace, Trace, TraceFilter, U64, FeeHistory}; use std::sync::Arc; +use serde::Serialize; use thiserror::Error; +use url::Url; +use ethers_core::types::transaction::eip2930::AccessListWithGasUsed; -use ethers_providers::{FromErr, Middleware}; +use ethers_providers::{EscalatingPending, EscalationPolicy, FilterWatcher, FromErr, LogQuery, Middleware, PendingTransaction, Provider, ProviderError}; +use ethers_providers::erc::ERCNFT; type TimeLagResult = Result>; @@ -110,6 +111,10 @@ where &self.inner } + fn connection(&self) -> String { + self.inner.connection() + } + async fn get_block_number(&self) -> Result { self.inner() .get_block_number() diff --git a/ethers-middleware/src/transformer/middleware.rs b/ethers-middleware/src/transformer/middleware.rs index 3847b9415..ae2a07a14 100644 --- a/ethers-middleware/src/transformer/middleware.rs +++ b/ethers-middleware/src/transformer/middleware.rs @@ -1,8 +1,14 @@ +use std::fmt::Debug; use super::{Transformer, TransformerError}; use async_trait::async_trait; +use serde::de::DeserializeOwned; +use serde::Serialize; use ethers_core::types::{transaction::eip2718::TypedTransaction, *}; -use ethers_providers::{FromErr, Middleware, PendingTransaction}; +use ethers_providers::{EscalatingPending, EscalationPolicy, FilterKind, FilterWatcher, FromErr, LogQuery, Middleware, PendingTransaction, Provider, ProviderError, PubsubClient, SubscriptionStream}; use thiserror::Error; +use url::Url; +use ethers_core::types::transaction::eip2930::AccessListWithGasUsed; +use ethers_providers::erc::ERCNFT; #[derive(Debug)] /// Middleware used for intercepting transaction requests and transforming them to be executed by @@ -54,6 +60,10 @@ where &self.inner } + fn connection(&self) -> String { + self.inner.connection() + } + async fn send_transaction + Send + Sync>( &self, tx: Tx, diff --git a/ethers-providers/src/lib.rs b/ethers-providers/src/lib.rs index d28ffe907..f21d0213f 100644 --- a/ethers-providers/src/lib.rs +++ b/ethers-providers/src/lib.rs @@ -163,6 +163,8 @@ pub trait Middleware: Sync + Send + Debug { self.inner().provider() } + fn connection(&self) -> String; + fn default_sender(&self) -> Option
{ self.inner().default_sender() } diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs index 40388b76b..68ecb809c 100644 --- a/ethers-providers/src/provider.rs +++ b/ethers-providers/src/provider.rs @@ -1,11 +1,4 @@ -use crate::{ - call_raw::CallBuilder, - ens, erc, maybe, - pubsub::{PubsubClient, SubscriptionStream}, - stream::{FilterWatcher, DEFAULT_LOCAL_POLL_INTERVAL, DEFAULT_POLL_INTERVAL}, - FromErr, Http as HttpProvider, JsonRpcClient, JsonRpcClientWrapper, LogQuery, MockProvider, - PendingTransaction, QuorumProvider, RwClient, SyncingStatus, -}; +use crate::{call_raw::CallBuilder, ens, erc, maybe, pubsub::{PubsubClient, SubscriptionStream}, stream::{FilterWatcher, DEFAULT_LOCAL_POLL_INTERVAL, DEFAULT_POLL_INTERVAL}, FromErr, Http as HttpProvider, JsonRpcClient, JsonRpcClientWrapper, LogQuery, MockProvider, PendingTransaction, QuorumProvider, RwClient, SyncingStatus, EscalationPolicy, EscalatingPending}; #[cfg(all(not(target_arch = "wasm32"), feature = "ws"))] use crate::transports::Authorization; @@ -318,6 +311,10 @@ impl Middleware for Provider

{ self.from } + fn connection(&self) -> String { + self.inner.connection() + } + ////// Blockchain Status // // Functions for querying the state of the blockchain From 642e43fa0f13e4e7b54c7480fa7ad0369f6f78b8 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 12 Feb 2024 18:50:50 +0400 Subject: [PATCH 08/13] WIP --- ethers-encryption/README.md | 195 +----------------- ethers-middleware/src/gas_escalator/mod.rs | 14 +- .../src/gas_oracle/middleware.rs | 12 +- ethers-middleware/src/nonce_manager.rs | 11 +- ethers-middleware/src/policy.rs | 10 +- ethers-middleware/src/signer.rs | 16 +- ethers-middleware/src/timelag/mod.rs | 15 +- .../src/transformer/middleware.rs | 12 +- ethers-providers/Cargo.toml | 1 + ethers-providers/src/lib.rs | 16 +- ethers-providers/src/provider.rs | 32 ++- ethers-providers/src/transports/http.rs | 4 - ethers-providers/src/transports/ipc.rs | 4 - ethers-providers/src/transports/mock.rs | 4 - ethers-providers/src/transports/quorum.rs | 4 - ethers-providers/src/transports/retry.rs | 4 - ethers-providers/src/transports/rw.rs | 4 - ethers-providers/src/transports/ws.rs | 4 - 18 files changed, 56 insertions(+), 306 deletions(-) diff --git a/ethers-encryption/README.md b/ethers-encryption/README.md index a13e15e0a..5ac1e88c8 100644 --- a/ethers-encryption/README.md +++ b/ethers-encryption/README.md @@ -1,196 +1,3 @@ #

ethers.rs

-**Complete Ethereum and Celo wallet implementation and utilities in Rust** - -![Github Actions](https://github.com/gakonst/ethers-rs/workflows/Tests/badge.svg) -[![Telegram Chat](https://img.shields.io/endpoint?color=neon&style=flat-square&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Fethers_rs)](https://t.me/ethers_rs) -[![Crates.io][crates-badge]][crates-url] - -[crates-badge]: https://img.shields.io/crates/v/ethers.svg -[crates-url]: https://crates.io/crates/ethers - -## Documentation - -Extensive documentation and examples are available [here](https://docs.rs/ethers). - -Alternatively, you may clone the repository and run `cd ethers/ && cargo doc --open` - -You can also run any of the examples by executing: `cargo run -p ethers --example ` - -## Add ethers-rs to your repository - -```toml -[dependencies] - -ethers = "1.0.0" -``` - - - -## Running the tests - -Tests require the following installed: - -1. [`solc`](https://solidity.readthedocs.io/en/latest/installing-solidity.html) (>=0.8.10). We also recommend using [solc-select](https://github.com/crytic/solc-select) for more flexibility. -2. [`anvil`](https://github.com/foundry-rs/foundry/blob/master/anvil/README.md) -3. [`geth`](https://github.com/ethereum/go-ethereum) - -In addition, it is recommended that you set the `ETHERSCAN_API_KEY` environment variable -for [the abigen via Etherscan](https://github.com/gakonst/ethers-rs/blob/master/ethers-contract/tests/abigen.rs) tests. -You can get one [here](https://etherscan.io/apis). - -### EVM-compatible chains support - -There are many chains live which are Ethereum JSON-RPC & EVM compatible, but do not yet have -support for [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) Typed Transactions. This means -that transactions submitted to them by default in ethers-rs will have invalid serialization. To -address that, you must use the `legacy` feature flag: - -```toml -[dependencies] - -ethers = { version = "1.0.0", features = ["legacy"] } -``` - -### Polygon support - -There is abigen support for Polygon and the Mumbai test network. It is recommended that you set the `POLYGONSCAN_API_KEY` environment variable. -You can get one [here](https://polygonscan.io/apis). - -### Avalanche support - -There is abigen support for Avalanche and the Fuji test network. It is recommended that you set the `SNOWTRACE_API_KEY` environment variable. -You can get one [here](https://snowtrace.io/apis). - -### Celo Support - -[Celo](http://celo.org/) support is turned on via the feature-flag `celo`: - -```toml -[dependencies] - -ethers = { version = "1.0.0", features = ["celo"] } -``` - -Celo's transactions differ from Ethereum transactions by including 3 new fields: - -- `fee_currency`: The currency fees are paid in (None for CELO, otherwise it's an Address) -- `gateway_fee_recipient`: The address of the fee recipient (None for no gateway fee paid) -- `gateway_fee`: Gateway fee amount (None for no gateway fee paid) - -The feature flag enables these additional fields in the transaction request builders and -in the transactions which are fetched over JSON-RPC. - -## Features - -- [x] Ethereum JSON-RPC Client -- [x] Interacting and deploying smart contracts -- [x] Type safe smart contract bindings code generation -- [x] Querying past events -- [x] Event monitoring as `Stream`s -- [x] ENS as a first class citizen -- [x] Celo support -- [x] Polygon support -- [x] Avalanche support -- [x] Websockets / `eth_subscribe` -- [x] Hardware Wallet Support -- [x] Parity APIs (`tracing`, `parity_blockWithReceipts`) -- [x] Geth TxPool API -- [ ] WASM Bindings (see note) -- [ ] FFI Bindings (see note) -- [ ] CLI for common operations - -### Websockets - -Websockets support is turned on via the feature-flag `ws`: - -```toml -[dependencies] - -ethers = { version = "1.0.0", features = ["ws"] } -``` - -### Interprocess Communication (IPC) - -IPC support is turned on via the feature-flag `ipc`: - -```toml -[dependencies] - -ethers = { version = "1.0.0", features = ["ipc"] } -``` - -### HTTP Secure (HTTPS) - -If you are looking to connect to a HTTPS endpoint, then you need to enable the `rustls` or `openssl` feature. -feature-flags. - -To enable `rustls`: - -```toml -[dependencies] - -ethers = { version = "1.0.0", features = ["rustls"] } -``` - -To enable `openssl`: - -```toml -[dependencies] - -ethers = { version = "1.0.0", features = ["openssl"] } -``` - -## Note on WASM and FFI bindings - -You should be able to build a wasm app that uses ethers-rs (see the [example](./examples/ethers-wasm) for reference). If ethers fails to -compile in WASM, please -[open an issue](https://github.com/gakonst/ethers-rs/issues/new/choose). -There is currently no plan to provide an official JS/TS-accessible library -interface. we believe [ethers.js](https://docs.ethers.io/v5/) serves that need -very well. - -Similarly, you should be able to build FFI bindings to ethers-rs. If ethers -fails to compile in c lib formats, please -[open an issue](https://github.com/gakonst/ethers-rs/issues/new/choose). -There is currently no plan to provide official FFI bindings, and as ethers-rs is -not yet stable 1.0.0, its interface may change significantly between versions. - -## Getting Help - -First, see if the answer to your question can be found in the [API documentation](https://docs.rs/ethers). If the answer -is not there, try opening an [issue](https://github.com/gakonst/ethers-rs/issues/new) with the question. - -Join the [ethers-rs telegram](https://t.me/ethers_rs) to chat with the community! - -## Contributing - -Thanks for your help improving the project! We are so happy to have you! We have -[a contributing guide](https://github.com/gakonst/ethers-rs/blob/master/CONTRIBUTING.md) to -help you get involved in the ethers-rs project. - -If you make a Pull Request, do not forget to add your changes in the [CHANGELOG](CHANGELOG.md) and ensure your code is -properly formatted with `cargo +nightly fmt` and clippy is happy `cargo clippy`, you can even try to let clippy fix simple -issues itself: `cargo +nightly clippy --fix -Z unstable-options` - -## Related Projects - -This library would not have been possible without the great work done in: - -- [`ethers.js`](https://github.com/ethers-io/ethers.js/) -- [`rust-web3`](https://github.com/tomusdrw/rust-web3/) -- [`ethcontract-rs`](https://github.com/gnosis/ethcontract-rs/) -- [`guac_rs`](https://github.com/althea-net/guac_rs/tree/master/web3/src/jsonrpc) - -A lot of the code was inspired and adapted from them, to a unified and opinionated interface, -built with async/await and std futures from the ground up. - -## Projects using ethers-rs - -- [Yield Liquidator](https://github.com/yieldprotocol/yield-liquidator/): Liquidator for Yield Protocol -- [MEV Inspect](https://github.com/flashbots/mev-inspect-rs/): Miner Extractable Value inspector -- [Ethers Flashbots](https://github.com/onbjerg/ethers-flashbots): Ethers middleware for [Flashbots](https://docs.flashbots.net) -- [Ethers Fireblocks](https://github.com/gakonst/ethers-fireblocks): Ethers middleware and signer for [Fireblocks](https://fireblocks.io)' API -- [Celo Threshold BLS DKG](https://github.com/celo-org/celo-threshold-bls-rs/): CLI for using Celo as a data availability network for the Joint-Feldman BLS DKG -- [Celo Plumo Prover](https://github.com/celo-org/plumo-prover): Creates Celo's ultralight client proof from on-chain data -- [Celo SNARK Setup Coordinator](https://github.com/celo-org/snark-setup-operator): Coordinator for executing a pipelined Groth16 SNARK setup +**Toolkit used for encryption and decryption in Swisstronik network** diff --git a/ethers-middleware/src/gas_escalator/mod.rs b/ethers-middleware/src/gas_escalator/mod.rs index 6bbc85e46..a71adbf3e 100644 --- a/ethers-middleware/src/gas_escalator/mod.rs +++ b/ethers-middleware/src/gas_escalator/mod.rs @@ -6,21 +6,15 @@ mod linear; pub use linear::LinearGasPrice; use async_trait::async_trait; -use ethers_core::types::{Address, Block, BlockId, BlockNumber, BlockTrace, Bytes, EIP1186ProofResponse, FeeHistory, Filter, GethDebugTracingOptions, GethTrace, Log, NameOrAddress, Signature, SyncingStatus, Trace, TraceFilter, TraceType, Transaction, TransactionReceipt, TransactionRequest, TxHash, TxpoolContent, TxpoolInspect, TxpoolStatus, U256, U64}; -use ethers_providers::{interval, FromErr, Middleware, PendingTransaction, StreamExt, Provider, EscalationPolicy, EscalatingPending, LogQuery, FilterKind, FilterWatcher, ProviderError, SubscriptionStream, PubsubClient}; +use ethers_core::types::{BlockId, TransactionRequest, TxHash, U256}; +use ethers_providers::{interval, FromErr, Middleware, PendingTransaction, StreamExt}; use futures_util::lock::Mutex; use instant::Instant; use std::{pin::Pin, sync::Arc}; -use std::fmt::Debug; -use serde::de::DeserializeOwned; -use serde::Serialize; use thiserror::Error; #[cfg(not(target_arch = "wasm32"))] use tokio::spawn; -use url::Url; -use ethers_core::types::transaction::eip2930::AccessListWithGasUsed; -use ethers_providers::erc::ERCNFT; #[cfg(target_arch = "wasm32")] type WatcherFuture<'a> = Pin + 'a>>; @@ -104,10 +98,6 @@ where &self.inner } - fn connection(&self) -> String { - self.inner.connection() - } - async fn send_transaction + Send + Sync>( &self, tx: T, diff --git a/ethers-middleware/src/gas_oracle/middleware.rs b/ethers-middleware/src/gas_oracle/middleware.rs index 84b4ddad3..272b01509 100644 --- a/ethers-middleware/src/gas_oracle/middleware.rs +++ b/ethers-middleware/src/gas_oracle/middleware.rs @@ -1,14 +1,8 @@ -use std::fmt::Debug; use super::{GasOracle, GasOracleError}; use async_trait::async_trait; -use serde::de::DeserializeOwned; -use serde::Serialize; use ethers_core::types::{transaction::eip2718::TypedTransaction, *}; -use ethers_providers::{EscalatingPending, EscalationPolicy, FilterKind, FilterWatcher, FromErr, LogQuery, Middleware, PendingTransaction, Provider, ProviderError, PubsubClient, SubscriptionStream}; +use ethers_providers::{FromErr, Middleware, PendingTransaction}; use thiserror::Error; -use url::Url; -use ethers_core::types::transaction::eip2930::AccessListWithGasUsed; -use ethers_providers::erc::ERCNFT; #[derive(Debug)] /// Middleware used for fetching gas prices over an API instead of `eth_gasPrice` @@ -62,10 +56,6 @@ where &self.inner } - fn connection(&self) -> String { - self.inner.connection() - } - async fn fill_transaction( &self, tx: &mut TypedTransaction, diff --git a/ethers-middleware/src/nonce_manager.rs b/ethers-middleware/src/nonce_manager.rs index 2c30d1377..50a5ae519 100644 --- a/ethers-middleware/src/nonce_manager.rs +++ b/ethers-middleware/src/nonce_manager.rs @@ -1,16 +1,11 @@ use async_trait::async_trait; use ethers_core::types::{transaction::eip2718::TypedTransaction, *}; -use ethers_providers::{EscalatingPending, EscalationPolicy, FilterKind, FilterWatcher, FromErr, LogQuery, Middleware, PendingTransaction, Provider, ProviderError, PubsubClient, SubscriptionStream}; +use ethers_providers::{FromErr, Middleware, PendingTransaction}; use std::{ fmt::Debug, sync::atomic::{AtomicBool, AtomicU64, Ordering}, }; -use serde::de::DeserializeOwned; -use serde::Serialize; use thiserror::Error; -use url::Url; -use ethers_core::types::transaction::eip2930::AccessListWithGasUsed; -use ethers_providers::erc::ERCNFT; #[derive(Debug)] /// Middleware used for calculating nonces locally, useful for signing multiple @@ -103,10 +98,6 @@ where &self.inner } - fn connection(&self) -> String { - self.inner.connection() - } - async fn fill_transaction( &self, tx: &mut TypedTransaction, diff --git a/ethers-middleware/src/policy.rs b/ethers-middleware/src/policy.rs index d4fc9bb18..fc69d52eb 100644 --- a/ethers-middleware/src/policy.rs +++ b/ethers-middleware/src/policy.rs @@ -1,11 +1,9 @@ -use ethers_core::types::{transaction::eip2718::TypedTransaction, BlockId, Address, U64, Block, H256}; -use ethers_providers::{EscalatingPending, EscalationPolicy, FromErr, Middleware, PendingTransaction, Provider}; +use ethers_core::types::{transaction::eip2718::TypedTransaction, BlockId}; +use ethers_providers::{FromErr, Middleware, PendingTransaction}; use async_trait::async_trait; use std::fmt::Debug; use thiserror::Error; -use url::Url; -use ethers_providers::erc::ERCNFT; /// Basic trait to ensure that transactions about to be sent follow certain rules. #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] @@ -97,10 +95,6 @@ where &self.inner } - fn connection(&self) -> String { - self.inner.connection() - } - /// This ensures the tx complies with the registered policy. /// If so then this simply delegates the transaction to the inner middleware async fn send_transaction + Send + Sync>( diff --git a/ethers-middleware/src/signer.rs b/ethers-middleware/src/signer.rs index 8d522ad0f..2549ba0f7 100644 --- a/ethers-middleware/src/signer.rs +++ b/ethers-middleware/src/signer.rs @@ -1,15 +1,13 @@ -use ethers_core::types::{transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed}, Address, BlockId, Bytes, Chain, Signature, TransactionRequest, U256, U64, Block, H256, Transaction, NameOrAddress, SyncingStatus, TransactionReceipt, BlockNumber, Filter, Log, EIP1186ProofResponse, TxpoolContent, TxpoolInspect, TxpoolStatus, GethDebugTracingOptions, GethTrace, TraceType, BlockTrace, Trace, TraceFilter, FeeHistory}; -use ethers_providers::{maybe, FromErr, Middleware, PendingTransaction, Provider, EscalationPolicy, EscalatingPending, LogQuery, FilterKind, FilterWatcher, ProviderError, SubscriptionStream, PubsubClient}; +use ethers_core::types::{ + transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed}, + Address, BlockId, Bytes, Chain, Signature, TransactionRequest, U256, +}; +use ethers_providers::{maybe, FromErr, Middleware, PendingTransaction}; use ethers_signers::Signer; use std::convert::TryFrom; -use std::fmt::Debug; use async_trait::async_trait; -use serde::de::DeserializeOwned; -use serde::Serialize; use thiserror::Error; -use url::Url; -use ethers_providers::erc::ERCNFT; #[derive(Clone, Debug)] /// Middleware used for locally signing transactions, compatible with any implementer @@ -228,10 +226,6 @@ where &self.inner } - fn connection(&self) -> String { - self.inner.connection() - } - /// Returns the client's address fn default_sender(&self) -> Option
{ Some(self.address) diff --git a/ethers-middleware/src/timelag/mod.rs b/ethers-middleware/src/timelag/mod.rs index 27dcdbf82..6c1e90b81 100644 --- a/ethers-middleware/src/timelag/mod.rs +++ b/ethers-middleware/src/timelag/mod.rs @@ -1,13 +1,12 @@ use async_trait::async_trait; -use ethers_core::types::{transaction::eip2718::TypedTransaction, Block, BlockId, BlockNumber, Bytes, FilterBlockOption, NameOrAddress, Transaction, TransactionReceipt, TxHash, U256, Address, SyncingStatus, Signature, Filter, Log, EIP1186ProofResponse, TxpoolContent, TxpoolInspect, TxpoolStatus, GethDebugTracingOptions, GethTrace, TraceType, BlockTrace, Trace, TraceFilter, U64, FeeHistory}; +use ethers_core::types::{ + transaction::eip2718::TypedTransaction, Block, BlockId, BlockNumber, Bytes, FilterBlockOption, + NameOrAddress, Transaction, TransactionReceipt, TxHash, U256, +}; use std::sync::Arc; -use serde::Serialize; use thiserror::Error; -use url::Url; -use ethers_core::types::transaction::eip2930::AccessListWithGasUsed; -use ethers_providers::{EscalatingPending, EscalationPolicy, FilterWatcher, FromErr, LogQuery, Middleware, PendingTransaction, Provider, ProviderError}; -use ethers_providers::erc::ERCNFT; +use ethers_providers::{FromErr, Middleware}; type TimeLagResult = Result>; @@ -111,10 +110,6 @@ where &self.inner } - fn connection(&self) -> String { - self.inner.connection() - } - async fn get_block_number(&self) -> Result { self.inner() .get_block_number() diff --git a/ethers-middleware/src/transformer/middleware.rs b/ethers-middleware/src/transformer/middleware.rs index ae2a07a14..3847b9415 100644 --- a/ethers-middleware/src/transformer/middleware.rs +++ b/ethers-middleware/src/transformer/middleware.rs @@ -1,14 +1,8 @@ -use std::fmt::Debug; use super::{Transformer, TransformerError}; use async_trait::async_trait; -use serde::de::DeserializeOwned; -use serde::Serialize; use ethers_core::types::{transaction::eip2718::TypedTransaction, *}; -use ethers_providers::{EscalatingPending, EscalationPolicy, FilterKind, FilterWatcher, FromErr, LogQuery, Middleware, PendingTransaction, Provider, ProviderError, PubsubClient, SubscriptionStream}; +use ethers_providers::{FromErr, Middleware, PendingTransaction}; use thiserror::Error; -use url::Url; -use ethers_core::types::transaction::eip2930::AccessListWithGasUsed; -use ethers_providers::erc::ERCNFT; #[derive(Debug)] /// Middleware used for intercepting transaction requests and transforming them to be executed by @@ -60,10 +54,6 @@ where &self.inner } - fn connection(&self) -> String { - self.inner.connection() - } - async fn send_transaction + Send + Sync>( &self, tx: Tx, diff --git a/ethers-providers/Cargo.toml b/ethers-providers/Cargo.toml index a49da8d29..6279c572f 100644 --- a/ethers-providers/Cargo.toml +++ b/ethers-providers/Cargo.toml @@ -69,6 +69,7 @@ tempfile = "3.3.0" [features] default = ["ws", "rustls"] celo = ["ethers-core/celo"] +swisstronik = [] ws = ["tokio-tungstenite", "futures-channel"] ipc = ["tokio/io-util", "bytes", "futures-channel"] diff --git a/ethers-providers/src/lib.rs b/ethers-providers/src/lib.rs index f21d0213f..680a4d2a0 100644 --- a/ethers-providers/src/lib.rs +++ b/ethers-providers/src/lib.rs @@ -69,9 +69,6 @@ pub trait JsonRpcClient: Debug + Send + Sync { where T: Debug + Serialize + Send + Sync, R: DeserializeOwned; - - /// Returns URL of connected node - fn connection(&self) -> String; } use ethers_core::types::*; @@ -163,8 +160,6 @@ pub trait Middleware: Sync + Send + Debug { self.inner().provider() } - fn connection(&self) -> String; - fn default_sender(&self) -> Option
{ self.inner().default_sender() } @@ -680,6 +675,17 @@ pub trait CeloMiddleware: Middleware { } } +#[cfg(feature = "swisstronik")] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +pub trait SwisstronikMiddleware: Middleware { + async fn get_node_public_key( + &self + ) -> Result { + self.provider().get_node_public_key().await.map_err(FromErr::from) + } +} + pub use test_provider::{GOERLI, MAINNET, ROPSTEN}; /// Pre-instantiated Infura HTTP clients which rotate through multiple API keys diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs index 68ecb809c..10eaf0073 100644 --- a/ethers-providers/src/provider.rs +++ b/ethers-providers/src/provider.rs @@ -7,6 +7,8 @@ use crate::transports::{HttpRateLimitRetryPolicy, RetryClient}; #[cfg(feature = "celo")] use crate::CeloMiddleware; +#[cfg(feature = "swisstronik")] +use crate::SwisstronikMiddleware; use crate::Middleware; use async_trait::async_trait; @@ -103,6 +105,15 @@ impl FromErr for ProviderError { } } +pub trait GetConn{ + fn get_conn(&self) -> String; +} +impl GetConn for Provider { + fn get_conn(&self) -> String { + self.inner.url().to_string() + } +} + impl Debug for Provider

{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -292,6 +303,18 @@ impl CeloMiddleware for Provider

{ } } + +#[cfg(feature = "swisstronik")] +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +impl SwisstronikMiddleware for Provider

{ + async fn get_node_public_key( + &self + ) -> Result { + self.request("swtr_getNodePublicKey", []).await + } +} + #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] impl Middleware for Provider

{ @@ -311,10 +334,6 @@ impl Middleware for Provider

{ self.from } - fn connection(&self) -> String { - self.inner.connection() - } - ////// Blockchain Status // // Functions for querying the state of the blockchain @@ -569,7 +588,7 @@ impl Middleware for Provider

{ let chain_id = self.get_chainid().await?; if chain_id.as_u32() == 1291 && tx.data().is_some() && tx.to().is_some() { // Obtain node public key and encrypt tx.data - let node_url = self.inner.connection(); + let node_url = self.get_conn(); let (encrypted_data, encryption_key) = ethers_encryption::encrypt_data( node_url.as_str(), @@ -621,9 +640,10 @@ impl Middleware for Provider

{ block: Option, ) -> Result { let chain_id = self.get_chainid().await?; + if chain_id.as_u32() == 1291 && tx.data().is_some() && tx.to().is_some() { // Obtain node public key and encrypt tx.data - let node_url = self.inner.connection(); + let node_url = ""; let (encrypted_data, _) = ethers_encryption::encrypt_data(node_url.as_str(), tx.data().unwrap()) .await .ok_or_else(|| ProviderError::CustomError(String::from("Cannot encrypt transaction data")))?; diff --git a/ethers-providers/src/transports/http.rs b/ethers-providers/src/transports/http.rs index fa411702e..e697bb896 100644 --- a/ethers-providers/src/transports/http.rs +++ b/ethers-providers/src/transports/http.rs @@ -106,10 +106,6 @@ impl JsonRpcClient for Provider { Ok(res) } - - fn connection(&self) -> String { - self.url.to_string() - } } impl Provider { diff --git a/ethers-providers/src/transports/ipc.rs b/ethers-providers/src/transports/ipc.rs index eb873b58d..acd111cf0 100644 --- a/ethers-providers/src/transports/ipc.rs +++ b/ethers-providers/src/transports/ipc.rs @@ -105,10 +105,6 @@ impl JsonRpcClient for Ipc { // Parse JSON response. Ok(serde_json::from_str(res.get())?) } - - fn connection(&self) -> String { - "127.0.0.1:8545".to_string() - } } impl PubsubClient for Ipc { diff --git a/ethers-providers/src/transports/mock.rs b/ethers-providers/src/transports/mock.rs index b9a0a8336..e6ff8f5c8 100644 --- a/ethers-providers/src/transports/mock.rs +++ b/ethers-providers/src/transports/mock.rs @@ -56,10 +56,6 @@ impl JsonRpcClient for MockProvider { Ok(res) } - - fn connection(&self) -> String { - "http://127.0.0.1:8545".to_string() - } } impl MockProvider { diff --git a/ethers-providers/src/transports/quorum.rs b/ethers-providers/src/transports/quorum.rs index c43a3f2c7..c564eb1fd 100644 --- a/ethers-providers/src/transports/quorum.rs +++ b/ethers-providers/src/transports/quorum.rs @@ -588,10 +588,6 @@ where } } } - - fn connection(&self) -> String { - "127.0.0.1:8545".to_string() - } } // A stream that returns a value and the weight of its provider diff --git a/ethers-providers/src/transports/retry.rs b/ethers-providers/src/transports/retry.rs index d684e57b9..1d42af61b 100644 --- a/ethers-providers/src/transports/retry.rs +++ b/ethers-providers/src/transports/retry.rs @@ -335,10 +335,6 @@ where } } } - - fn connection(&self) -> String { - self.inner.connection() - } } /// Implements [RetryPolicy] that will retry requests that errored with diff --git a/ethers-providers/src/transports/rw.rs b/ethers-providers/src/transports/rw.rs index 300842c5c..f54a96ebc 100644 --- a/ethers-providers/src/transports/rw.rs +++ b/ethers-providers/src/transports/rw.rs @@ -124,8 +124,4 @@ where _ => self.r.request(method, params).await.map_err(RwClientError::Read), } } - - fn connection(&self) -> String { - self.r.connection() - } } diff --git a/ethers-providers/src/transports/ws.rs b/ethers-providers/src/transports/ws.rs index ebd980ede..d05970ec9 100644 --- a/ethers-providers/src/transports/ws.rs +++ b/ethers-providers/src/transports/ws.rs @@ -187,10 +187,6 @@ impl JsonRpcClient for Ws { // parse it Ok(serde_json::from_str(res.get())?) } - - fn connection(&self) -> String { - "127.0.0.1:8545".to_string() - } } impl PubsubClient for Ws { From 86b41f87ca7cfd69c7429bfa18690bf947b36b41 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 12 Feb 2024 19:10:28 +0400 Subject: [PATCH 09/13] Proper estimate_gas --- ethers-encryption/src/lib.rs | 68 ++------------------------------ ethers-providers/src/provider.rs | 66 +++++++++++++++++-------------- 2 files changed, 39 insertions(+), 95 deletions(-) diff --git a/ethers-encryption/src/lib.rs b/ethers-encryption/src/lib.rs index 24515a1cc..ff89a5f0c 100644 --- a/ethers-encryption/src/lib.rs +++ b/ethers-encryption/src/lib.rs @@ -31,17 +31,9 @@ struct NodePublicKeyResponse { /// Returns Some(encrypted_data, used_key) if encryption was successful, returns None in case /// of error pub async fn encrypt_data( - node_url: &str, + node_public_key: [u8;32], data: &[u8], ) -> Option<(Vec, [u8; KEY_SIZE])> { - // Get node public key - let node_public_key = match get_node_public_key(node_url).await { - Some(pk) => pk, - None => { - return None; - } - }; - // Generate random encryption key let mut rng = OsRng; let mut key_material = [0u8; KEY_SIZE]; @@ -76,14 +68,7 @@ pub async fn encrypt_data( /// * data – ciphertext, received from node /// /// Returns Some(decrypted_data) in case of success, otherwise returns None -pub async fn decrypt_data(node_url: &str, encryption_key: [u8; KEY_SIZE], data: &[u8]) -> Option> { - let node_public_key = match get_node_public_key(node_url).await { - Some(pk) => pk, - None => { - return None; - } - }; - +pub async fn decrypt_data(node_public_key: [u8;32], encryption_key: [u8; KEY_SIZE], data: &[u8]) -> Option> { // Decrypt data let decrypted = encryption::decrypt_ecdh( encryption_key, @@ -100,56 +85,9 @@ pub async fn decrypt_data(node_url: &str, encryption_key: [u8; KEY_SIZE], data: } } -/// Requests node public key, which will be used for derivation of shared -/// encryption key -/// -/// * url – URL of JSON-RPC to obtain node public key -/// -/// Returns Some(node_public_key) in case of success, otherwise returns None -pub async fn get_node_public_key(url: &str) -> Option<[u8; KEY_SIZE]> { - let url = match Url::parse(url) { - Ok(url) => url, - Err(err) => { - println!("Cannot obtain node public key. Reason: {:?}", err); - return None; - } - }; - - let body = serde_json::json!({ - "id": 1, - "jsonrpc": "2.0", - "method": "eth_getNodePublicKey", - "params": ["latest"], - }); - - let client = Client::new(); - let response = client.post(url).json(&body).send().await.ok()?; - - if !response.status().is_success() { - println!("Request failed with status: {}", response.status()); - return None; - } - - let api_response: NodePublicKeyResponse = response.json().await.ok()?; - let result_str = api_response.result.trim_start_matches("0x"); - - let res = match hex::decode(result_str) { - Ok(res) => res, - Err(err) => { - println!("Cannot obtain node public key. Reason: {:?}", err); - return None; - } - }; - - Some(convert_to_fixed_size_array(res)) -} - -fn convert_to_fixed_size_array(data: Vec) -> [u8; KEY_SIZE] { +pub fn convert_to_fixed_size_array(data: Vec) -> [u8; KEY_SIZE] { let mut fixed_array = [0u8; KEY_SIZE]; fixed_array.copy_from_slice(&data[..KEY_SIZE]); fixed_array } -fn bytearray_to_const_size(v: Vec) -> Option<[T; N]> { - v.try_into().ok() -} diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs index 10eaf0073..6a696b2f3 100644 --- a/ethers-providers/src/provider.rs +++ b/ethers-providers/src/provider.rs @@ -9,6 +9,9 @@ use crate::transports::{HttpRateLimitRetryPolicy, RetryClient}; use crate::CeloMiddleware; #[cfg(feature = "swisstronik")] use crate::SwisstronikMiddleware; +#[cfg(feature = "swisstronik")] +use ethers_encryption::convert_to_fixed_size_array; + use crate::Middleware; use async_trait::async_trait; @@ -36,6 +39,9 @@ use std::{ use tracing::trace; use tracing_futures::Instrument; + + + #[derive(Copy, Clone)] pub enum NodeClient { Geth, @@ -105,15 +111,6 @@ impl FromErr for ProviderError { } } -pub trait GetConn{ - fn get_conn(&self) -> String; -} -impl GetConn for Provider { - fn get_conn(&self) -> String { - self.inner.url().to_string() - } -} - impl Debug for Provider

{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -310,8 +307,10 @@ impl CeloMiddleware for Provider

{ impl SwisstronikMiddleware for Provider

{ async fn get_node_public_key( &self - ) -> Result { - self.request("swtr_getNodePublicKey", []).await + ) -> Result<[u8;32], ProviderError> { + let resp: String = self.request("eth_getNodePublicKey", []).await?; + let converted = convert_to_fixed_size_array(hex::decode(resp.trim_start_matches("0x"))?); + Ok(converted) } } @@ -634,36 +633,42 @@ impl Middleware for Provider

{ /// required (as a U256) to send it This is free, but only an estimate. Providing too little /// gas will result in a transaction being rejected (while still consuming all provided /// gas). + #[cfg(not(feature = "swisstronik"))] async fn estimate_gas( &self, tx: &TypedTransaction, block: Option, ) -> Result { - let chain_id = self.get_chainid().await?; - - if chain_id.as_u32() == 1291 && tx.data().is_some() && tx.to().is_some() { + let tx = utils::serialize(tx); + // Some nodes (e.g. old Optimism clients) don't support a block ID being passed as a param, + // so refrain from defaulting to BlockNumber::Latest. + let params = if let Some(block_id) = block { + vec![tx, utils::serialize(&block_id)] + } else { + vec![tx] + }; + self.request("eth_estimateGas", params).await + } + #[cfg(feature = "swisstronik")] + async fn estimate_gas( + &self, + tx: &TypedTransaction, + block: Option, + ) -> Result { + let tx = if tx.data().is_some() && tx.to().is_some() { // Obtain node public key and encrypt tx.data - let node_url = ""; - let (encrypted_data, _) = ethers_encryption::encrypt_data(node_url.as_str(), tx.data().unwrap()) + let node_public_key = self.get_node_public_key().await?; + let (encrypted_data, _) = ethers_encryption::encrypt_data(node_public_key, tx.data().unwrap()) .await .ok_or_else(|| ProviderError::CustomError(String::from("Cannot encrypt transaction data")))?; // Update tx.data field let mut encrypted_tx = tx.clone(); let encrypted_tx = encrypted_tx.set_data(encrypted_data.into()); - - let tx = utils::serialize(encrypted_tx); - // Some nodes (e.g. old Optimism clients) don't support a block ID being passed as a param, - // so refrain from defaulting to BlockNumber::Latest. - let params = if let Some(block_id) = block { - vec![tx, utils::serialize(&block_id)] - } else { - vec![tx] - }; - return self.request("eth_estimateGas", params).await - } - - let tx = utils::serialize(tx); + utils::serialize(encrypted_tx) + } else { + utils::serialize(tx) + }; // Some nodes (e.g. old Optimism clients) don't support a block ID being passed as a param, // so refrain from defaulting to BlockNumber::Latest. let params = if let Some(block_id) = block { @@ -671,9 +676,10 @@ impl Middleware for Provider

{ } else { vec![tx] }; - self.request("eth_estimateGas", params).await + return self.request("eth_estimateGas", params).await } + async fn create_access_list( &self, tx: &TypedTransaction, From 659ffaeb25c9fe6bfaebd52a5bad9b3cadaf97ff Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 12 Feb 2024 19:34:16 +0400 Subject: [PATCH 10/13] Fix build, proper signer --- ethers-middleware/Cargo.toml | 1 + ethers-middleware/src/signer.rs | 46 ++++++++++++++++++--- ethers-providers/src/lib.rs | 2 +- ethers-providers/src/provider.rs | 68 +++++++++++++++----------------- 4 files changed, 74 insertions(+), 43 deletions(-) diff --git a/ethers-middleware/Cargo.toml b/ethers-middleware/Cargo.toml index 355e8d372..d8cb4d773 100644 --- a/ethers-middleware/Cargo.toml +++ b/ethers-middleware/Cargo.toml @@ -57,3 +57,4 @@ tokio = { version = "1.18", default-features = false, features = ["rt", "macros" [features] celo = ["ethers-core/celo", "ethers-providers/celo", "ethers-signers/celo", "ethers-contract/celo"] +swisstronik = ["ethers-providers/swisstronik"] \ No newline at end of file diff --git a/ethers-middleware/src/signer.rs b/ethers-middleware/src/signer.rs index 2549ba0f7..3feaefd60 100644 --- a/ethers-middleware/src/signer.rs +++ b/ethers-middleware/src/signer.rs @@ -9,6 +9,10 @@ use std::convert::TryFrom; use async_trait::async_trait; use thiserror::Error; +#[cfg(feature = "swisstronik")] +use ethers_providers::SwisstronikMiddleware; + + #[derive(Clone, Debug)] /// Middleware used for locally signing transactions, compatible with any implementer /// of the [`Signer`] trait. @@ -99,6 +103,12 @@ pub enum SignerMiddlewareError { /// Thrown if the signer's chain_id is different than the chain_id of the transaction #[error("specified chain_id is different than the signer's chain_id")] DifferentChainID, + /// Thrown if during encryption we couldn't obtain node public key + #[error("failed to get node public key")] + FailedNodePublicKey, + /// Thrown if during encryption there was an error + #[error("failed to encrypt")] + FailedToEncrypt, } // Helper functions for locally signing transactions @@ -125,6 +135,7 @@ where /// If the transaction does not have a chain id set, it sets it to the signer's chain id. /// Returns an error if the transaction's existing chain id does not match the signer's chain /// id. + #[cfg(not(feature = "swisstronik"))] async fn sign_transaction( &self, mut tx: TypedTransaction, @@ -142,13 +153,37 @@ where _ => {} } - if chain_id == 1291 && tx.to().is_some() && tx.data().is_some() { + let signature = + self.signer.sign_transaction(&tx).await.map_err(SignerMiddlewareError::SignerError)?; + + // Return the raw rlp-encoded signed transaction + Ok(tx.rlp_signed(&signature)) + } + + #[cfg(feature = "swisstronik")] + async fn sign_transaction( + &self, + mut tx: TypedTransaction, + ) -> Result> { +// compare chain_id and use signer's chain_id if the tranasaction's chain_id is None, + // return an error if they are not consistent + let chain_id = self.signer.chain_id(); + match tx.chain_id() { + Some(id) if id.as_u64() != chain_id => { + return Err(SignerMiddlewareError::DifferentChainID) + } + None => { + tx.set_chain_id(chain_id); + } + _ => {} + } + + if tx.to().is_some() && tx.data().is_some() { // Encryption transaction data in case of swisstronik network - let node_url = self.connection(); + let node_enc_key = self.provider().get_node_public_key().await.map_err(|_| SignerMiddlewareError::FailedNodePublicKey)?; // Encrypt call data in case of Swisstronik network - let (encrypted_data, _) = ethers_encryption::encrypt_data(node_url.as_str(), tx.data().unwrap()) - .await - .expect("Cannot encrypt transaction"); + let (encrypted_data, _) = ethers_encryption::encrypt_data(node_enc_key, tx.data().unwrap()) + .await.ok_or(SignerMiddlewareError::FailedToEncrypt)?; // Update call data tx.set_data(encrypted_data.into()); @@ -161,6 +196,7 @@ where Ok(tx.rlp_signed(&signature)) } + /// Returns the client's address pub fn address(&self) -> Address { self.address diff --git a/ethers-providers/src/lib.rs b/ethers-providers/src/lib.rs index 680a4d2a0..df5fd8a95 100644 --- a/ethers-providers/src/lib.rs +++ b/ethers-providers/src/lib.rs @@ -681,7 +681,7 @@ pub trait CeloMiddleware: Middleware { pub trait SwisstronikMiddleware: Middleware { async fn get_node_public_key( &self - ) -> Result { + ) -> Result<[u8;32], ProviderError> { self.provider().get_node_public_key().await.map_err(FromErr::from) } } diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs index 6a696b2f3..3e450254e 100644 --- a/ethers-providers/src/provider.rs +++ b/ethers-providers/src/provider.rs @@ -39,9 +39,6 @@ use std::{ use tracing::trace; use tracing_futures::Instrument; - - - #[derive(Copy, Clone)] pub enum NodeClient { Geth, @@ -308,7 +305,7 @@ impl SwisstronikMiddleware for Provider

{ async fn get_node_public_key( &self ) -> Result<[u8;32], ProviderError> { - let resp: String = self.request("eth_getNodePublicKey", []).await?; + let resp: String = self.request("eth_getNodePublicKey", ()).await?; let converted = convert_to_fixed_size_array(hex::decode(resp.trim_start_matches("0x"))?); Ok(converted) } @@ -579,56 +576,53 @@ impl Middleware for Provider

{ /// Sends the read-only (constant) transaction to a single Ethereum node and return the result /// (as bytes) of executing it. This is free, since it does not change any state on the /// blockchain. + #[cfg(not(feature = "swisstronik"))] async fn call( &self, tx: &TypedTransaction, block: Option, ) -> Result { - let chain_id = self.get_chainid().await?; - if chain_id.as_u32() == 1291 && tx.data().is_some() && tx.to().is_some() { - // Obtain node public key and encrypt tx.data - let node_url = self.get_conn(); + let tx = utils::serialize(tx); + let block = utils::serialize(&block.unwrap_or_else(|| BlockNumber::Latest.into())); + self.request("eth_call", [tx, block]).await + } - let (encrypted_data, encryption_key) = ethers_encryption::encrypt_data( - node_url.as_str(), - tx.data().unwrap() - ).await.ok_or_else(|| ProviderError::CustomError(String::from("Cannot encrypt transaction data")))?; + #[cfg(feature= "swisstronik")] + async fn call( + &self, + tx: &TypedTransaction, + block: Option, + ) -> Result { + if tx.data().is_some() && tx.to().is_some() { + // Obtain node public key and encrypt tx.data + let node_public_key = self.get_node_public_key().await?; + let (encrypted_data, encryption_key) = ethers_encryption::encrypt_data(node_public_key, tx.data().unwrap()) + .await + .ok_or_else(|| ProviderError::CustomError(String::from("Cannot encrypt transaction data")))?; // Update tx.data field let mut encrypted_tx = tx.clone(); let encrypted_tx = encrypted_tx.set_data(encrypted_data.into()); - let tx = utils::serialize(encrypted_tx); let block = utils::serialize(&block.unwrap_or_else(|| BlockNumber::Latest.into())); - let response: Result = self.request("eth_call", [tx, block]).await; - - match response { - Ok(result) => { - let decrypted_data = ethers_encryption::decrypt_data( - node_url.as_str(), - encryption_key, - &result, - ).await; - return match decrypted_data { - Some(data) => { - Ok(data.into()) - }, - None => { - Err(ProviderError::CustomError("Cannot decrypt node response".to_string())) - } - } + let response: Vec = self.request("eth_call", [tx, block]).await?; + let decrypted_data = ethers_encryption::decrypt_data(node_public_key, encryption_key, &response).await; + match decrypted_data { + Some(data) => { + Ok(data.into()) }, - _ => {}, + None => { + Err(ProviderError::CustomError("Cannot decrypt node response".to_string())) + } } - - return response + } else { + let tx = utils::serialize(tx); + let block = utils::serialize(&block.unwrap_or_else(|| BlockNumber::Latest.into())); + self.request("eth_call", [tx, block]).await } - - let tx = utils::serialize(tx); - let block = utils::serialize(&block.unwrap_or_else(|| BlockNumber::Latest.into())); - self.request("eth_call", [tx, block]).await } + /// Sends a transaction to a single Ethereum node and return the estimated amount of gas /// required (as a U256) to send it This is free, but only an estimate. Providing too little /// gas will result in a transaction being rejected (while still consuming all provided From d105f4e27771fe598002c9e4cbfaac11a4693328 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 12 Feb 2024 19:38:49 +0400 Subject: [PATCH 11/13] Make encryption optional --- ethers-middleware/Cargo.toml | 4 ++-- ethers-providers/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ethers-middleware/Cargo.toml b/ethers-middleware/Cargo.toml index d8cb4d773..c11944232 100644 --- a/ethers-middleware/Cargo.toml +++ b/ethers-middleware/Cargo.toml @@ -20,7 +20,7 @@ ethers-core = { version = "^1.0.0", path = "../ethers-core", default-features = ethers-etherscan = { version = "^1.0.0", path = "../ethers-etherscan", default-features = false } ethers-providers = { version = "^1.0.0", path = "../ethers-providers", default-features = false } ethers-signers = { version = "^1.0.0", path = "../ethers-signers", default-features = false } -ethers-encryption = { version = "^1.0.0", path = "../ethers-encryption", default-features = false } +ethers-encryption = { version = "^1.0.0", path = "../ethers-encryption", default-features = false , optional = true} async-trait = { version = "0.1.50", default-features = false } auto_impl = { version = "0.5.0", default-features = false } @@ -57,4 +57,4 @@ tokio = { version = "1.18", default-features = false, features = ["rt", "macros" [features] celo = ["ethers-core/celo", "ethers-providers/celo", "ethers-signers/celo", "ethers-contract/celo"] -swisstronik = ["ethers-providers/swisstronik"] \ No newline at end of file +swisstronik = ["ethers-providers/swisstronik", "ethers-encryption"] \ No newline at end of file diff --git a/ethers-providers/Cargo.toml b/ethers-providers/Cargo.toml index 6279c572f..5d4c1bc2a 100644 --- a/ethers-providers/Cargo.toml +++ b/ethers-providers/Cargo.toml @@ -16,7 +16,7 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] ethers-core = { version = "^1.0.0", path = "../ethers-core", default-features = false } -ethers-encryption = { version = "^1.0.0", path = "../ethers-encryption", default-features = false } +ethers-encryption = { version = "^1.0.0", path = "../ethers-encryption", default-features = false , optional = true} async-trait = { version = "0.1.50", default-features = false } hex = { version = "0.4.3", default-features = false, features = ["std"] } @@ -69,7 +69,7 @@ tempfile = "3.3.0" [features] default = ["ws", "rustls"] celo = ["ethers-core/celo"] -swisstronik = [] +swisstronik = [ "ethers-encryption"] ws = ["tokio-tungstenite", "futures-channel"] ipc = ["tokio/io-util", "bytes", "futures-channel"] From b77a823bd801cba0f32796c7ba6b1a7b4e502496 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 13 Feb 2024 13:38:41 +0400 Subject: [PATCH 12/13] Trim the fat --- .cargo/config.toml | 2 -- ethers-encryption/.clippy.toml | 1 - ethers-encryption/.gitignore | 4 ---- ethers-encryption/release.toml | 2 -- ethers-encryption/rustfmt.toml | 9 --------- ethers-encryption/src/derivation.rs | 4 ++-- ethers-encryption/src/encryption.rs | 13 ++++++------- ethers-encryption/src/lib.rs | 17 +++++------------ 8 files changed, 13 insertions(+), 39 deletions(-) delete mode 100644 .cargo/config.toml delete mode 100644 ethers-encryption/.clippy.toml delete mode 100644 ethers-encryption/.gitignore delete mode 100644 ethers-encryption/release.toml delete mode 100644 ethers-encryption/rustfmt.toml diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index c91c3f38b..000000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[net] -git-fetch-with-cli = true diff --git a/ethers-encryption/.clippy.toml b/ethers-encryption/.clippy.toml deleted file mode 100644 index 6bfeada7f..000000000 --- a/ethers-encryption/.clippy.toml +++ /dev/null @@ -1 +0,0 @@ -msrv = "1.62" diff --git a/ethers-encryption/.gitignore b/ethers-encryption/.gitignore deleted file mode 100644 index 026535e5e..000000000 --- a/ethers-encryption/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/target -.vscode -/.envrc -.idea diff --git a/ethers-encryption/release.toml b/ethers-encryption/release.toml deleted file mode 100644 index d55f4e95d..000000000 --- a/ethers-encryption/release.toml +++ /dev/null @@ -1,2 +0,0 @@ -consolidate-commits = false -consolidate-pushes = true diff --git a/ethers-encryption/rustfmt.toml b/ethers-encryption/rustfmt.toml deleted file mode 100644 index e70aee8cc..000000000 --- a/ethers-encryption/rustfmt.toml +++ /dev/null @@ -1,9 +0,0 @@ -reorder_imports = true -imports_granularity = "Crate" -use_small_heuristics = "Max" -comment_width = 100 -wrap_comments = true -binop_separator = "Back" -trailing_comma = "Vertical" -trailing_semicolon = false -use_field_init_shorthand = true diff --git a/ethers-encryption/src/derivation.rs b/ethers-encryption/src/derivation.rs index 7a6027bc7..d87131888 100644 --- a/ethers-encryption/src/derivation.rs +++ b/ethers-encryption/src/derivation.rs @@ -1,4 +1,4 @@ -use deoxys::aead::{Aead, KeyInit, Payload}; +use deoxys::aead::KeyInit; use sha2::Sha256; use hmac::{Hmac, Mac}; @@ -23,7 +23,7 @@ pub fn derive_shared_secret(private_key: [u8; KEY_SIZE], public_key: [u8; KEY_SI /// Derives encryption key using KDF pub fn derive_encryption_key(private_key: &[u8], salt: &[u8]) -> [u8; KEY_SIZE] { - let mut kdf = ::new_from_slice(salt).unwrap(); + let mut kdf = ::new_from_slice(salt).unwrap(); kdf.update(private_key); let mut derived_key = [0u8; KEY_SIZE]; let digest = kdf.finalize(); diff --git a/ethers-encryption/src/encryption.rs b/ethers-encryption/src/encryption.rs index 0a1e6087b..eb59562b0 100644 --- a/ethers-encryption/src/encryption.rs +++ b/ethers-encryption/src/encryption.rs @@ -1,16 +1,15 @@ -use sha2::Sha256; -use hmac::{Hmac, Mac}; +use hmac::{Mac}; use rand::{rngs::OsRng, RngCore}; use deoxys::aead::generic_array::GenericArray; use deoxys::aead::{Aead, KeyInit, Payload}; use deoxys::DeoxysII256; -use crate::{KEY_SIZE, TX_KEY_PREFIX, NONCE_SIZE, TAG_SIZE }; +use crate::{KEY_SIZE, TX_KEY_PREFIX, NONCE_SIZE, TAG_SIZE}; use crate::derivation::{ derive_shared_secret, derive_encryption_key, - x25519_private_to_public + x25519_private_to_public, }; pub fn encrypt_ecdh( @@ -73,9 +72,9 @@ pub fn deoxys_decrypt( encrypted_data: &[u8], ) -> Result, deoxys::Error> { let nonce = &encrypted_data[0..NONCE_SIZE]; - let aad = &encrypted_data[NONCE_SIZE..NONCE_SIZE+TAG_SIZE]; - let ciphertext = &encrypted_data[NONCE_SIZE+TAG_SIZE..]; + let aad = &encrypted_data[NONCE_SIZE..NONCE_SIZE + TAG_SIZE]; + let ciphertext = &encrypted_data[NONCE_SIZE + TAG_SIZE..]; let payload = Payload { msg: ciphertext, aad }; let key = GenericArray::from_slice(private_key); - DeoxysII256::new(key).decrypt( GenericArray::from_slice(nonce), payload) + DeoxysII256::new(key).decrypt(GenericArray::from_slice(nonce), payload) } diff --git a/ethers-encryption/src/lib.rs b/ethers-encryption/src/lib.rs index ff89a5f0c..c189dbc24 100644 --- a/ethers-encryption/src/lib.rs +++ b/ethers-encryption/src/lib.rs @@ -1,5 +1,3 @@ -use serde_json::json; -use reqwest::{Client, Url}; use serde::{Deserialize, Serialize}; use rand::{rngs::OsRng, RngCore}; use std::convert::TryInto; @@ -18,11 +16,6 @@ pub const NONCE_SIZE: usize = 15; /// Default size of private / public key pub const KEY_SIZE: usize = 32; -#[derive(Debug, Deserialize)] -struct NodePublicKeyResponse { - result: String, -} - /// Encrypts provided transaction or call data field /// /// * node_url - URL of JSON-RPC to obtain node public key @@ -31,7 +24,7 @@ struct NodePublicKeyResponse { /// Returns Some(encrypted_data, used_key) if encryption was successful, returns None in case /// of error pub async fn encrypt_data( - node_public_key: [u8;32], + node_public_key: [u8; 32], data: &[u8], ) -> Option<(Vec, [u8; KEY_SIZE])> { // Generate random encryption key @@ -42,14 +35,14 @@ pub async fn encrypt_data( // Derive encryption key let encryption_key = derivation::derive_encryption_key( &key_material, - USER_KEY_PREFIX.as_bytes() + USER_KEY_PREFIX.as_bytes(), ); // Encrypt data let encrypted = encryption::encrypt_ecdh( encryption_key.clone(), node_public_key, - data + data, ); match encrypted { @@ -68,12 +61,12 @@ pub async fn encrypt_data( /// * data – ciphertext, received from node /// /// Returns Some(decrypted_data) in case of success, otherwise returns None -pub async fn decrypt_data(node_public_key: [u8;32], encryption_key: [u8; KEY_SIZE], data: &[u8]) -> Option> { +pub async fn decrypt_data(node_public_key: [u8; 32], encryption_key: [u8; KEY_SIZE], data: &[u8]) -> Option> { // Decrypt data let decrypted = encryption::decrypt_ecdh( encryption_key, node_public_key, - data + data, ); match decrypted { From a16f1db64a1980287f8693977898c4dbce819f4e Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 14 Feb 2024 10:55:38 +0400 Subject: [PATCH 13/13] Fix getNodePublicKey, add test for it --- ethers-providers/src/provider.rs | 2 +- ethers-providers/tests/provider.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs index 3e450254e..9ed32b798 100644 --- a/ethers-providers/src/provider.rs +++ b/ethers-providers/src/provider.rs @@ -305,7 +305,7 @@ impl SwisstronikMiddleware for Provider

{ async fn get_node_public_key( &self ) -> Result<[u8;32], ProviderError> { - let resp: String = self.request("eth_getNodePublicKey", ()).await?; + let resp: String = self.request("eth_getNodePublicKey", ["latest"]).await?; let converted = convert_to_fixed_size_array(hex::decode(resp.trim_start_matches("0x"))?); Ok(converted) } diff --git a/ethers-providers/tests/provider.rs b/ethers-providers/tests/provider.rs index 4878964b2..c94f01610 100644 --- a/ethers-providers/tests/provider.rs +++ b/ethers-providers/tests/provider.rs @@ -115,6 +115,21 @@ mod eth_tests { } } + +#[cfg(feature = "swisstronik")] +mod swisstronik_tests { + use super::*; + use ethers_providers::SwisstronikMiddleware; + + #[tokio::test] + async fn get_block() { + let provider = + Provider::::try_from("https://json-rpc.testnet.swisstronik.com").unwrap(); + + provider.get_node_public_key().await.unwrap(); + } +} + #[cfg(feature = "celo")] mod celo_tests { use super::*;