From a7c405f36927ee589dbd5643f10d7927a9c7d42a Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Wed, 24 Jul 2024 14:58:22 -0300 Subject: [PATCH 01/82] initial BasicSigner implementation --- Cargo.lock | 359 +++++++++++++++++++++++++++++++-------- Cargo.toml | 2 +- crates/signer/Cargo.toml | 19 +++ crates/signer/signer.rs | 39 +++++ 4 files changed, 345 insertions(+), 74 deletions(-) create mode 100644 crates/signer/Cargo.toml create mode 100644 crates/signer/signer.rs diff --git a/Cargo.lock b/Cargo.lock index 8d18f687..89c1a4d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,10 +81,24 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a016bfa21193744d4c38b3f3ab845462284d129e5e23c7cc0fafca7e92d9db37" dependencies = [ - "alloy-eips", + "alloy-eips 0.1.2", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 0.1.2", + "c-kzg", + "serde", +] + +[[package]] +name = "alloy-consensus" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58047cc851e58c26224521d1ecda466e3d746ebca0274cd5427aa660a88c353" +dependencies = [ + "alloy-eips 0.2.0", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.2.0", "c-kzg", "serde", ] @@ -97,12 +111,31 @@ checksum = "e47b2a620fd588d463ccf0f5931b41357664b293a8d31592768845a2a101bb9e" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", - "alloy-network", + "alloy-network 0.1.2", "alloy-primitives", - "alloy-provider", - "alloy-rpc-types-eth", + "alloy-provider 0.1.2", + "alloy-rpc-types-eth 0.1.2", "alloy-sol-types", - "alloy-transport", + "alloy-transport 0.1.2", + "futures", + "futures-util", + "thiserror", +] + +[[package]] +name = "alloy-contract" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa5d42d9f87896536234b0fac1a84ad9d9dc7a4b27839cac35d0899e64ddf083" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-network 0.2.0", + "alloy-primitives", + "alloy-provider 0.2.0", + "alloy-rpc-types-eth 0.2.0", + "alloy-sol-types", + "alloy-transport 0.2.0", "futures", "futures-util", "thiserror", @@ -110,9 +143,9 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6e6436a9530f25010d13653e206fab4c9feddacf21a54de8d7311b275bc56b" +checksum = "413902aa18a97569e60f679c23f46a18db1656d87ab4d4e49d0e1e52042f66df" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -133,7 +166,22 @@ checksum = "32d6d8118b83b0489cfb7e6435106948add2b35217f4a5004ef895f613f60299" dependencies = [ "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 0.1.2", + "c-kzg", + "once_cell", + "serde", + "sha2", +] + +[[package]] +name = "alloy-eips" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32a3e14fa0d152d00bd8daf605eb74ad397efb0f54bd7155585823dddb4401e" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.2.0", "c-kzg", "once_cell", "serde", @@ -142,9 +190,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaeaccd50238126e3a0ff9387c7c568837726ad4f4e399b528ca88104d6c25ef" +checksum = "bc05b04ac331a9f07e3a4036ef7926e49a8bf84a99a1ccfc7e2ab55a5fcbb372" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -165,19 +213,52 @@ dependencies = [ "tracing", ] +[[package]] +name = "alloy-json-rpc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e76a9feec2352c78545d1a37415699817bae8dc41654bd1bfe57d6cdd5433bd" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", + "thiserror", + "tracing", +] + [[package]] name = "alloy-network" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc122cbee2b8523854cc11d87bcd5773741602c553d2d2d106d82eeb9c16924a" dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-json-rpc", + "alloy-consensus 0.1.2", + "alloy-eips 0.1.2", + "alloy-json-rpc 0.1.2", "alloy-primitives", - "alloy-rpc-types-eth", - "alloy-serde", - "alloy-signer", + "alloy-rpc-types-eth 0.1.2", + "alloy-serde 0.1.2", + "alloy-signer 0.1.2", + "alloy-sol-types", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "thiserror", +] + +[[package]] +name = "alloy-network" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3223d71dc78f464b2743418d0be8b5c894313e272105a6206ad5e867d67b3ce2" +dependencies = [ + "alloy-consensus 0.2.0", + "alloy-eips 0.2.0", + "alloy-json-rpc 0.2.0", + "alloy-primitives", + "alloy-rpc-types-eth 0.2.0", + "alloy-serde 0.2.0", + "alloy-signer 0.2.0", "alloy-sol-types", "async-trait", "auto_impl", @@ -187,9 +268,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f783611babedbbe90db3478c120fb5f5daacceffc210b39adc0af4fe0da70bad" +checksum = "ccb3ead547f4532bc8af961649942f0b9c16ee9226e26caa3f38420651cc0bf4" dependencies = [ "alloy-rlp", "bytes", @@ -214,16 +295,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d5af289798fe8783acd0c5f10644d9d26f54a12bc52a083e4f3b31718e9bf92" dependencies = [ "alloy-chains", - "alloy-consensus", - "alloy-eips", - "alloy-json-rpc", - "alloy-network", + "alloy-consensus 0.1.2", + "alloy-eips 0.1.2", + "alloy-json-rpc 0.1.2", + "alloy-network 0.1.2", "alloy-primitives", "alloy-pubsub", - "alloy-rpc-client", - "alloy-rpc-types-eth", - "alloy-transport", - "alloy-transport-http", + "alloy-rpc-client 0.1.2", + "alloy-rpc-types-eth 0.1.2", + "alloy-transport 0.1.2", + "alloy-transport-http 0.1.2", "alloy-transport-ws", "async-stream", "async-trait", @@ -241,15 +322,44 @@ dependencies = [ "url", ] +[[package]] +name = "alloy-provider" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29da7457d853cb8199ec04b227d5d2ef598be3e59fc2bbad70c8be213292f32" +dependencies = [ + "alloy-chains", + "alloy-consensus 0.2.0", + "alloy-eips 0.2.0", + "alloy-json-rpc 0.2.0", + "alloy-network 0.2.0", + "alloy-primitives", + "alloy-rpc-client 0.2.0", + "alloy-rpc-types-eth 0.2.0", + "alloy-transport 0.2.0", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "futures", + "futures-utils-wasm", + "lru", + "pin-project", + "serde", + "serde_json", + "tokio", + "tracing", +] + [[package]] name = "alloy-pubsub" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702f330b7da123a71465ab9d39616292f8344a2811c28f2cc8d8438a69d79e35" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.1.2", "alloy-primitives", - "alloy-transport", + "alloy-transport 0.1.2", "bimap", "futures", "serde", @@ -288,11 +398,11 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b40fcb53b2a9d0a78a4968b2eca8805a4b7011b9ee3fdfa2acaf137c5128f36b" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.1.2", "alloy-primitives", "alloy-pubsub", - "alloy-transport", - "alloy-transport-http", + "alloy-transport 0.1.2", + "alloy-transport-http 0.1.2", "alloy-transport-ws", "futures", "pin-project", @@ -306,14 +416,33 @@ dependencies = [ "url", ] +[[package]] +name = "alloy-rpc-client" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a9e609524fa31c2c70eb24c0da60796809193ad4787a6dfe6d0db0d3ac112d" +dependencies = [ + "alloy-json-rpc 0.2.0", + "alloy-transport 0.2.0", + "alloy-transport-http 0.2.0", + "futures", + "pin-project", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", +] + [[package]] name = "alloy-rpc-types" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50f2fbe956a3e0f0975c798f488dc6be96b669544df3737e18f4a325b42f4c86" dependencies = [ - "alloy-rpc-types-eth", - "alloy-serde", + "alloy-rpc-types-eth 0.1.2", + "alloy-serde 0.1.2", ] [[package]] @@ -322,11 +451,29 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "083f443a83b9313373817236a8f4bea09cca862618e9177d822aee579640a5d6" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 0.1.2", + "alloy-eips 0.1.2", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 0.1.2", + "alloy-sol-types", + "itertools 0.13.0", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "605fa8462732bb8fd0645a9941e12961e079d45ae6a44634c826f8229c187bdf" +dependencies = [ + "alloy-consensus 0.2.0", + "alloy-eips 0.2.0", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.2.0", "alloy-sol-types", "itertools 0.13.0", "serde", @@ -345,6 +492,17 @@ dependencies = [ "serde_json", ] +[[package]] +name = "alloy-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c5b9057acc02aee1b8aac2b5a0729cb0f73d080082c111313e5d1f92a96630" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + [[package]] name = "alloy-signer" version = "0.1.2" @@ -359,16 +517,30 @@ dependencies = [ "thiserror", ] +[[package]] +name = "alloy-signer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37f10592696f4ab8b687d5a8ab55e998a14ea0ca5f8eb20ad74a96ad671bb54a" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror", +] + [[package]] name = "alloy-signer-local" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d40a37dc216c269b8a7244047cb1c18a9c69f7a0332ab2c4c2aa4cbb1a31468b" dependencies = [ - "alloy-consensus", - "alloy-network", + "alloy-consensus 0.1.2", + "alloy-network 0.1.2", "alloy-primitives", - "alloy-signer", + "alloy-signer 0.1.2", "async-trait", "k256", "rand", @@ -377,9 +549,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bad41a7c19498e3f6079f7744656328699f8ea3e783bdd10d85788cd439f572" +checksum = "2b40397ddcdcc266f59f959770f601ce1280e699a91fc1862f29cef91707cd09" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -391,9 +563,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9899da7d011b4fe4c406a524ed3e3f963797dbc93b45479d60341d3a27b252" +checksum = "867a5469d61480fea08c7333ffeca52d5b621f5ca2e44f271b117ec1fc9a0525" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", @@ -410,9 +582,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32d595768fdc61331a132b6f65db41afae41b9b97d36c21eb1b955c422a7e60" +checksum = "2e482dc33a32b6fadbc0f599adea520bd3aaa585c141a80b404d0a3e3fa72528" dependencies = [ "alloy-json-abi", "const-hex", @@ -427,18 +599,19 @@ dependencies = [ [[package]] name = "alloy-sol-type-parser" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baa2fbd22d353d8685bd9fee11ba2d8b5c3b1d11e56adb3265fcf1f32bfdf404" +checksum = "cbcba3ca07cf7975f15d871b721fb18031eec8bce51103907f6dcce00b255d98" dependencies = [ + "serde", "winnow 0.6.13", ] [[package]] name = "alloy-sol-types" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a49042c6d3b66a9fe6b2b5a8bf0d39fc2ae1ee0310a2a26ffedd79fb097878dd" +checksum = "a91ca40fa20793ae9c3841b83e74569d1cc9af29a2f5237314fd3452d51e38c7" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -453,7 +626,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245af9541f0a0dbd5258669c80dfe3af118164cacec978a520041fc130550deb" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.1.2", "base64 0.22.1", "futures-util", "futures-utils-wasm", @@ -465,14 +638,33 @@ dependencies = [ "url", ] +[[package]] +name = "alloy-transport" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b44b0f6f4a2593b258fa7b6cae8968e6a4c404d9ef4f5bc74401f2d04fa23fa" +dependencies = [ + "alloy-json-rpc 0.2.0", + "base64 0.22.1", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", +] + [[package]] name = "alloy-transport-http" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5619c017e1fdaa1db87f9182f4f0ed97c53d674957f4902fba655e972d359c6c" dependencies = [ - "alloy-json-rpc", - "alloy-transport", + "alloy-json-rpc 0.1.2", + "alloy-transport 0.1.2", "reqwest 0.12.5", "serde_json", "tower", @@ -480,6 +672,16 @@ dependencies = [ "url", ] +[[package]] +name = "alloy-transport-http" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d8f1eefa8cb9e7550740ee330feba4fed303a77ad3085707546f9152a88c380" +dependencies = [ + "alloy-transport 0.2.0", + "url", +] + [[package]] name = "alloy-transport-ws" version = "0.1.2" @@ -487,7 +689,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c0aff8af5be5e58856c5cdd1e46db2c67c7ecd3a652d9100b4822c96c899947" dependencies = [ "alloy-pubsub", - "alloy-transport", + "alloy-transport 0.1.2", "futures", "http 1.1.0", "rustls 0.23.10", @@ -1359,14 +1561,14 @@ dependencies = [ name = "eigen-client-avsregistry" version = "0.0.1-alpha" dependencies = [ - "alloy-contract", - "alloy-network", + "alloy-contract 0.1.2", + "alloy-network 0.1.2", "alloy-primitives", - "alloy-provider", + "alloy-provider 0.1.2", "alloy-rpc-types", - "alloy-signer", + "alloy-signer 0.1.2", "alloy-signer-local", - "alloy-transport-http", + "alloy-transport-http 0.1.2", "ark-bn254", "ark-ff 0.4.2", "eigen-chainio-utils", @@ -1386,10 +1588,10 @@ dependencies = [ name = "eigen-client-elcontracts" version = "0.0.1-alpha" dependencies = [ - "alloy-contract", - "alloy-eips", + "alloy-contract 0.1.2", + "alloy-eips 0.1.2", "alloy-primitives", - "alloy-provider", + "alloy-provider 0.1.2", "alloy-signer-local", "eigen-testing-utils", "eigen-types", @@ -1539,7 +1741,7 @@ name = "eigen-services-operatorsinfo" version = "0.0.1-alpha" dependencies = [ "alloy-primitives", - "alloy-provider", + "alloy-provider 0.1.2", "alloy-rpc-types", "anyhow", "eigen-client-avsregistry", @@ -1549,14 +1751,25 @@ dependencies = [ "tokio", ] +[[package]] +name = "eigen-signer" +version = "0.0.1-alpha" +dependencies = [ + "alloy-contract 0.2.0", + "alloy-primitives", + "hex", + "hex-literal", + "k256", +] + [[package]] name = "eigen-testing-utils" version = "0.0.1-alpha" dependencies = [ - "alloy-network", + "alloy-network 0.1.2", "alloy-primitives", - "alloy-provider", - "alloy-transport-http", + "alloy-provider 0.1.2", + "alloy-transport-http 0.1.2", "eigen-utils", "once_cell", ] @@ -1576,12 +1789,12 @@ dependencies = [ name = "eigen-utils" version = "0.0.1-alpha" dependencies = [ - "alloy-contract", - "alloy-network", - "alloy-provider", + "alloy-contract 0.1.2", + "alloy-network 0.1.2", + "alloy-provider 0.1.2", "alloy-signer-local", "alloy-sol-types", - "alloy-transport-http", + "alloy-transport-http 0.1.2", "reqwest 0.12.5", ] @@ -2008,7 +2221,7 @@ name = "examples-avsregistry-write" version = "0.0.1-alpha" dependencies = [ "alloy-primitives", - "alloy-provider", + "alloy-provider 0.1.2", "ark-bn254", "ark-ff 0.4.2", "eigen-chainio-utils", @@ -4522,9 +4735,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d71e19bca02c807c9faa67b5a47673ff231b6e7449b251695188522f1dc44b2" +checksum = "c837dc8852cb7074e46b444afb81783140dab12c58867b49fb3898fbafedf7ea" dependencies = [ "paste", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 89b036bc..59a2fc10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ members = [ "crates/chainio/clients/avsregistry/", "examples/avsregistry-read", "examples/avsregistry-write", "examples/anvil-utils" -] +, "crates/signer"] resolver = "2" diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml new file mode 100644 index 00000000..d8118504 --- /dev/null +++ b/crates/signer/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "eigen-signer" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +repository.workspace = true + +[dependencies] +alloy-contract = "0.2.0" +alloy-primitives = "0.7.7" +hex = "0.4.3" +hex-literal = "0.4.1" +k256 = "0.13.3" + +[lib] +path = "signer.rs" + +[lints] +workspace = true diff --git a/crates/signer/signer.rs b/crates/signer/signer.rs new file mode 100644 index 00000000..9cd551dd --- /dev/null +++ b/crates/signer/signer.rs @@ -0,0 +1,39 @@ +use alloy_primitives::Address; +use k256::ecdsa::SigningKey; + +#[derive(PartialEq, Debug)] +pub struct BasicSigner { + private_key: SigningKey, + account_address: Address, +} + +impl BasicSigner { + pub fn new(private_key: SigningKey) -> Self { + let account_address = Address::from_private_key(&private_key); + BasicSigner { + private_key, + account_address, + } + } +} + +#[cfg(test)] +mod test { + use crate::BasicSigner; + use alloy_primitives::Address; + use hex_literal::hex; + use k256::ecdsa::SigningKey; + + #[test] + fn signer_from_private_key() { + let signing_key = SigningKey::from_bytes( + &hex!("4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318").into(), + ) + .unwrap(); + let expected_address = + Address::from_slice(&hex::decode("2c7536E3605D9C16a7a3D7b1898e529396a65c23").unwrap()); + let basic_signer = BasicSigner::new(signing_key); + + assert_eq!(basic_signer.account_address, expected_address); + } +} From f89560970fa154d4eabce7f1918f3305edd78474 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Wed, 24 Jul 2024 15:03:00 -0300 Subject: [PATCH 02/82] remove hex crate --- Cargo.lock | 1 - Cargo.toml | 39 --------------------------------------- crates/signer/Cargo.toml | 1 - crates/signer/signer.rs | 2 +- 4 files changed, 1 insertion(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 89c1a4d0..fa5de364 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1757,7 +1757,6 @@ version = "0.0.1-alpha" dependencies = [ "alloy-contract 0.2.0", "alloy-primitives", - "hex", "hex-literal", "k256", ] diff --git a/Cargo.toml b/Cargo.toml index 59a2fc10..1a7ee686 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,30 +56,19 @@ quote = "1.0" metrics = "0.21.1" once_cell = "1.17" reqwest = "0.12.4" -reth = {git = "https://github.com/paradigmxyz/reth"} -prometheus-client = "0.22.2" -bn254 = {git = "https://github.com/sedaprotocol/bn254"} -eigen-metrics = {version = "0.0.1-alpha", path = "crates/metrics/"} serde = {version = "1.0.197" , features = ["derive"]} eigen-chainio-utils = {path = "crates/chainio/utils/"} eigen-client-avsregistry = {path = "crates/chainio/clients/avsregistry"} eigen-client-elcontracts = {path = "crates/chainio/clients/elcontracts"} -eigen-client-eth = {path = "crates/chainio/clients/eth"} -eigen-client-fireblocks = {path = "crates/chainio/clients/fireblocks"} -eigen-contract-bindings = { path = "crates/contracts/bindings/"} eigen-types = {path = "crates/types/"} eigen-crypto-bls = {path = "crates/crypto/bls/"} eigen-crypto-bn254 = {path = "crates/crypto/bn254/"} -eigen-crypto-keystore = {path = "crates/crypto/keystore/"} eigen-utils = {path = "crates/utils/"} eigen-metrics-collectors-economic = {path = "crates/metrics/collectors/economic"} -eigen-metrics-collectors-rpc-calls = {path = "crates/metrics/collectors/rpc_calls"} eigen-services-avsregistry = {path = "crates/services/avsregistry"} -eigen-services-bls_aggregation = {path = "crates/services/bls_aggregation"} eigen-services-operatorsinfo = {path = "crates/services/operatorsinfo"} eigen-metrics-derive = {path = "crates/metrics/metrics-derive"} eigen-testing-utils = {path = "testing/testing-utils"} -info-operator-service = {path = "examples/info-operator-service"} tokio = {version = "1.37.0" , features = ["test-util", "full","sync"] } futures-util = "0.3.30" thiserror = "1.0" @@ -89,27 +78,11 @@ hyper = "0.14.25" #misc parking_lot = "0.12" - -#alloy -alloy-chains = "0.1.15" alloy-primitives = "0.7.2" -alloy-dyn-abi = "0.7.2" alloy-sol-types = "0.7.2" -alloy-rlp = "0.3.4" -alloy-trie = "0.4" alloy-rpc-types = { version = "0.1", default-features = false, features = [ "eth", ] } -alloy-rpc-types-anvil = { version = "0.1", default-features = false } -alloy-rpc-types-beacon = { version = "0.1", default-features = false } -alloy-rpc-types-admin = { version = "0.1", default-features = false } -alloy-rpc-types-txpool = { version = "0.1", default-features = false } -alloy-serde = { version = "0.1", default-features = false } -alloy-rpc-types-engine = { version = "0.1", default-features = false } -alloy-rpc-types-eth = { version = "0.1", default-features = false } -alloy-rpc-types-trace = { version = "0.1", default-features = false } -alloy-genesis = { version = "0.1", default-features = false } -alloy-node-bindings = { version = "0.1", default-features = false } alloy-provider = { version = "0.1", default-features = false, features = [ "reqwest", ] } @@ -117,19 +90,7 @@ alloy-eips = { version = "0.1", default-features = false } alloy-signer = { version = "0.1", default-features = false } alloy-signer-local = { version = "0.1", default-features = false } alloy-network = { version = "0.1", default-features = false } -alloy-consensus = { version = "0.1", default-features = false } -alloy-transport = { version = "0.1" } alloy-transport-http = { version = "0.1", features = [ "reqwest-rustls-tls", ], default-features = false } -alloy-transport-ws = { version = "0.1", default-features = false } -alloy-transport-ipc = { version = "0.1", default-features = false } -alloy-pubsub = { version = "0.1", default-features = false } -alloy-json-rpc = { version = "0.1", default-features = false } -alloy-rpc-client = { version = "0.1", default-features = false } alloy-contract = { version = "0.1", default-features = false } - -# examples -avsregistry-read = {path = "examples/avsregistry-read"} -avsregistry-write = {path = "examples/avsregistry-write"} -anvil-utils = {path = "examples/anvil-utils"} diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index d8118504..a8bedd04 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -8,7 +8,6 @@ repository.workspace = true [dependencies] alloy-contract = "0.2.0" alloy-primitives = "0.7.7" -hex = "0.4.3" hex-literal = "0.4.1" k256 = "0.13.3" diff --git a/crates/signer/signer.rs b/crates/signer/signer.rs index 9cd551dd..59de2019 100644 --- a/crates/signer/signer.rs +++ b/crates/signer/signer.rs @@ -31,7 +31,7 @@ mod test { ) .unwrap(); let expected_address = - Address::from_slice(&hex::decode("2c7536E3605D9C16a7a3D7b1898e529396a65c23").unwrap()); + Address::from_slice(&hex!("2c7536E3605D9C16a7a3D7b1898e529396a65c23")); let basic_signer = BasicSigner::new(signing_key); assert_eq!(basic_signer.account_address, expected_address); From 60459882cae477b1d6b1b7b20031795e63c7c99a Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Wed, 24 Jul 2024 17:33:21 -0300 Subject: [PATCH 03/82] replace signer with signerV2 implementation --- Cargo.lock | 31 +++++++++++++--- crates/signer/Cargo.toml | 8 +++-- crates/signer/signer.rs | 39 -------------------- crates/signer/src/lib.rs | 1 + crates/signer/src/signer.rs | 71 +++++++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 47 deletions(-) delete mode 100644 crates/signer/signer.rs create mode 100644 crates/signer/src/lib.rs create mode 100644 crates/signer/src/signer.rs diff --git a/Cargo.lock b/Cargo.lock index fa5de364..9f2e7b2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -547,6 +547,22 @@ dependencies = [ "thiserror", ] +[[package]] +name = "alloy-signer-local" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b537f3e55f30753578f4623d5f66ddad8fa582af3fa6b15bad23dd1b9775228" +dependencies = [ + "alloy-consensus 0.2.0", + "alloy-network 0.2.0", + "alloy-primitives", + "alloy-signer 0.2.0", + "async-trait", + "k256", + "rand", + "thiserror", +] + [[package]] name = "alloy-sol-macro" version = "0.7.7" @@ -1567,7 +1583,7 @@ dependencies = [ "alloy-provider 0.1.2", "alloy-rpc-types", "alloy-signer 0.1.2", - "alloy-signer-local", + "alloy-signer-local 0.1.2", "alloy-transport-http 0.1.2", "ark-bn254", "ark-ff 0.4.2", @@ -1592,7 +1608,7 @@ dependencies = [ "alloy-eips 0.1.2", "alloy-primitives", "alloy-provider 0.1.2", - "alloy-signer-local", + "alloy-signer-local 0.1.2", "eigen-testing-utils", "eigen-types", "eigen-utils", @@ -1755,8 +1771,13 @@ dependencies = [ name = "eigen-signer" version = "0.0.1-alpha" dependencies = [ + "alloy-consensus 0.2.0", "alloy-contract 0.2.0", + "alloy-network 0.2.0", "alloy-primitives", + "alloy-signer 0.1.2", + "alloy-signer-local 0.2.0", + "eth-keystore", "hex-literal", "k256", ] @@ -1791,7 +1812,7 @@ dependencies = [ "alloy-contract 0.1.2", "alloy-network 0.1.2", "alloy-provider 0.1.2", - "alloy-signer-local", + "alloy-signer-local 0.1.2", "alloy-sol-types", "alloy-transport-http 0.1.2", "reqwest 0.12.5", @@ -4467,9 +4488,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index a8bedd04..64ad4ffb 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -6,13 +6,15 @@ rust-version.workspace = true repository.workspace = true [dependencies] +alloy-consensus = "0.2.0" alloy-contract = "0.2.0" +alloy-network = "0.2.0" alloy-primitives = "0.7.7" +alloy-signer.workspace = true +alloy-signer-local = "0.2.0" +eth-keystore = "0.5.0" hex-literal = "0.4.1" k256 = "0.13.3" -[lib] -path = "signer.rs" - [lints] workspace = true diff --git a/crates/signer/signer.rs b/crates/signer/signer.rs deleted file mode 100644 index 59de2019..00000000 --- a/crates/signer/signer.rs +++ /dev/null @@ -1,39 +0,0 @@ -use alloy_primitives::Address; -use k256::ecdsa::SigningKey; - -#[derive(PartialEq, Debug)] -pub struct BasicSigner { - private_key: SigningKey, - account_address: Address, -} - -impl BasicSigner { - pub fn new(private_key: SigningKey) -> Self { - let account_address = Address::from_private_key(&private_key); - BasicSigner { - private_key, - account_address, - } - } -} - -#[cfg(test)] -mod test { - use crate::BasicSigner; - use alloy_primitives::Address; - use hex_literal::hex; - use k256::ecdsa::SigningKey; - - #[test] - fn signer_from_private_key() { - let signing_key = SigningKey::from_bytes( - &hex!("4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318").into(), - ) - .unwrap(); - let expected_address = - Address::from_slice(&hex!("2c7536E3605D9C16a7a3D7b1898e529396a65c23")); - let basic_signer = BasicSigner::new(signing_key); - - assert_eq!(basic_signer.account_address, expected_address); - } -} diff --git a/crates/signer/src/lib.rs b/crates/signer/src/lib.rs new file mode 100644 index 00000000..eef58b8f --- /dev/null +++ b/crates/signer/src/lib.rs @@ -0,0 +1 @@ +pub mod signer; diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs new file mode 100644 index 00000000..28588bb6 --- /dev/null +++ b/crates/signer/src/signer.rs @@ -0,0 +1,71 @@ +use alloy_signer_local::PrivateKeySigner; +use eth_keystore::decrypt_key; +use std::path::Path; + +#[derive(Debug)] +/// TODO: add docs +pub enum Config { + PrivateKey(String), + Keystore(String, String), + Web3(String, String), +} + +/// TODO: add docs +pub fn signer_from_config(c: Config) -> PrivateKeySigner { + // TODO: check chain id to select signer + // TODO: handle errors + match c { + Config::PrivateKey(key) => key.parse::().unwrap(), + Config::Keystore(path, password) => { + let keypath = Path::new(&path); + let private_key = decrypt_key(&keypath, password).unwrap(); + PrivateKeySigner::from_slice(&private_key).unwrap() + } + Config::Web3(_endpoint, _address) => { + todo!() + } + } +} + +#[cfg(test)] +mod test { + use super::{signer_from_config, Config}; + use alloy_consensus::TxLegacy; + use alloy_network::TxSignerSync; + use alloy_primitives::{address, bytes, U256}; + use alloy_signer::Signature; + use std::str::FromStr; + + #[test] + fn sign_transaction() { + let private_key = + "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7".to_owned(); + let config = Config::PrivateKey(private_key); + let mut tx = TxLegacy { + to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), + value: U256::from(1_000_000_000), + gas_limit: 2_000_000, + nonce: 0, + gas_price: 21_000_000_000, + input: bytes!(), + chain_id: Some(1), + }; + + let signer = signer_from_config(config); + + let signature = signer.sign_transaction_sync(&mut tx).unwrap(); + let expected_signature = Signature::from_rs_and_parity( + U256::from_str( + "99963972037857174861280476053118856715670512199525969754644366601434507134123", + ) + .unwrap(), + U256::from_str( + "54587766196536123534774489028213321677166972433316011091332824361042811624091", + ) + .unwrap(), + 37, + ) + .unwrap(); + assert_eq!(signature, expected_signature); + } +} From ffa49e303eb502536841b03cb169a6fa5f16877d Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Wed, 24 Jul 2024 17:55:50 -0300 Subject: [PATCH 04/82] add test for keystore --- crates/signer/mockdata/dummy.key.json | 19 ++++++++++++++++++ crates/signer/src/signer.rs | 29 ++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 crates/signer/mockdata/dummy.key.json diff --git a/crates/signer/mockdata/dummy.key.json b/crates/signer/mockdata/dummy.key.json new file mode 100644 index 00000000..ec14f71e --- /dev/null +++ b/crates/signer/mockdata/dummy.key.json @@ -0,0 +1,19 @@ +{ + "crypto": { + "cipher": "aes-128-ctr", + "cipherparams": { + "iv": "6087dab2f9fdbbfaddc31a909735c1e6" + }, + "ciphertext": "5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46", + "kdf": "pbkdf2", + "kdfparams": { + "c": 262144, + "dklen": 32, + "prf": "hmac-sha256", + "salt": "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd" + }, + "mac": "517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2" + }, + "id": "3198bc9c-6672-5ab3-d995-4942343ae5b6", + "version": 3 +} \ No newline at end of file diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 28588bb6..0f4dcbac 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -34,10 +34,12 @@ mod test { use alloy_network::TxSignerSync; use alloy_primitives::{address, bytes, U256}; use alloy_signer::Signature; + use alloy_signer_local::PrivateKeySigner; + use hex_literal::hex; use std::str::FromStr; #[test] - fn sign_transaction() { + fn sign_transaction_with_private_key() { let private_key = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7".to_owned(); let config = Config::PrivateKey(private_key); @@ -68,4 +70,29 @@ mod test { .unwrap(); assert_eq!(signature, expected_signature); } + + #[test] + fn sign_transaction_with_keystore() { + let path = "/Users/tomas/Lambda/eigen-rs/crates/signer/mockdata/dummy.key.json".to_owned(); + let password = "testpassword".to_owned(); + let config = Config::Keystore(path, password); + let mut tx = TxLegacy { + to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), + value: U256::from(1_000_000_000), + gas_limit: 2_000_000, + nonce: 0, + gas_price: 21_000_000_000, + input: bytes!(), + chain_id: Some(1), + }; + + let private_key = hex!("7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d"); + let expected_signer = PrivateKeySigner::from_slice(&private_key).unwrap(); + let expected_signature = expected_signer.sign_transaction_sync(&mut tx).unwrap(); + + let signer = signer_from_config(config); + let signature = signer.sign_transaction_sync(&mut tx).unwrap(); + + assert_eq!(signature, expected_signature); + } } From 59a48a1f2b3b6363971eb9ad63b73ddc97f90ed4 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Wed, 24 Jul 2024 18:18:26 -0300 Subject: [PATCH 05/82] update comments and minor changes --- Cargo.lock | 1 + crates/signer/Cargo.toml | 1 + crates/signer/mockdata/dummy.key.json | 2 +- crates/signer/src/signer.rs | 35 +++++++++++++++++++-------- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f2e7b2b..d3ffd42d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1780,6 +1780,7 @@ dependencies = [ "eth-keystore", "hex-literal", "k256", + "thiserror", ] [[package]] diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index 64ad4ffb..af69db7f 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -15,6 +15,7 @@ alloy-signer-local = "0.2.0" eth-keystore = "0.5.0" hex-literal = "0.4.1" k256 = "0.13.3" +thiserror.workspace = true [lints] workspace = true diff --git a/crates/signer/mockdata/dummy.key.json b/crates/signer/mockdata/dummy.key.json index ec14f71e..7895ed91 100644 --- a/crates/signer/mockdata/dummy.key.json +++ b/crates/signer/mockdata/dummy.key.json @@ -16,4 +16,4 @@ }, "id": "3198bc9c-6672-5ab3-d995-4942343ae5b6", "version": 3 -} \ No newline at end of file +} diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 0f4dcbac..781a4914 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -1,25 +1,40 @@ use alloy_signer_local::PrivateKeySigner; use eth_keystore::decrypt_key; use std::path::Path; +use thiserror::Error; #[derive(Debug)] -/// TODO: add docs +/// Represents the input params to create a signer pub enum Config { + /// Hexadecimal private key PrivateKey(String), + /// Keystore path and password Keystore(String, String), + /// Web3 endpoint and address Web3(String, String), } -/// TODO: add docs -pub fn signer_from_config(c: Config) -> PrivateKeySigner { +#[derive(Error, Debug)] +#[allow(missing_docs)] +pub enum SignerError { + #[error("invalid private key")] + InvalidPrivateKey, + #[error("invalid keystore password")] + InvalidPassword, +} + +/// Creates a signer from given config. +pub fn signer_from_config(c: Config) -> Result { // TODO: check chain id to select signer - // TODO: handle errors match c { - Config::PrivateKey(key) => key.parse::().unwrap(), + Config::PrivateKey(key) => key + .parse::() + .map_err(|_| SignerError::InvalidPrivateKey), Config::Keystore(path, password) => { let keypath = Path::new(&path); - let private_key = decrypt_key(&keypath, password).unwrap(); - PrivateKeySigner::from_slice(&private_key).unwrap() + let private_key = + decrypt_key(&keypath, password).map_err(|_| SignerError::InvalidPassword)?; + PrivateKeySigner::from_slice(&private_key).map_err(|_| SignerError::InvalidPrivateKey) } Config::Web3(_endpoint, _address) => { todo!() @@ -55,7 +70,7 @@ mod test { let signer = signer_from_config(config); - let signature = signer.sign_transaction_sync(&mut tx).unwrap(); + let signature = signer.unwrap().sign_transaction_sync(&mut tx).unwrap(); let expected_signature = Signature::from_rs_and_parity( U256::from_str( "99963972037857174861280476053118856715670512199525969754644366601434507134123", @@ -73,7 +88,7 @@ mod test { #[test] fn sign_transaction_with_keystore() { - let path = "/Users/tomas/Lambda/eigen-rs/crates/signer/mockdata/dummy.key.json".to_owned(); + let path = "mockdata/dummy.key.json".to_owned(); let password = "testpassword".to_owned(); let config = Config::Keystore(path, password); let mut tx = TxLegacy { @@ -91,7 +106,7 @@ mod test { let expected_signature = expected_signer.sign_transaction_sync(&mut tx).unwrap(); let signer = signer_from_config(config); - let signature = signer.sign_transaction_sync(&mut tx).unwrap(); + let signature = signer.unwrap().sign_transaction_sync(&mut tx).unwrap(); assert_eq!(signature, expected_signature); } From d86e4f9299d7a9ebc5a19269009b504bdd0dd3b3 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Wed, 24 Jul 2024 18:27:46 -0300 Subject: [PATCH 06/82] move signer_from_config into enum --- crates/signer/src/lib.rs | 5 +++++ crates/signer/src/signer.rs | 39 ++++++++++++++++++++----------------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/crates/signer/src/lib.rs b/crates/signer/src/lib.rs index eef58b8f..e78f58cd 100644 --- a/crates/signer/src/lib.rs +++ b/crates/signer/src/lib.rs @@ -1 +1,6 @@ +#![doc( + html_logo_url = "https://github.com/supernovahs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", + issue_tracker_base_url = "https://github.com/supernovahs/eigen-rs/issues/" +)] + pub mod signer; diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 781a4914..1850bc10 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -23,28 +23,31 @@ pub enum SignerError { InvalidPassword, } -/// Creates a signer from given config. -pub fn signer_from_config(c: Config) -> Result { - // TODO: check chain id to select signer - match c { - Config::PrivateKey(key) => key - .parse::() - .map_err(|_| SignerError::InvalidPrivateKey), - Config::Keystore(path, password) => { - let keypath = Path::new(&path); - let private_key = - decrypt_key(&keypath, password).map_err(|_| SignerError::InvalidPassword)?; - PrivateKeySigner::from_slice(&private_key).map_err(|_| SignerError::InvalidPrivateKey) - } - Config::Web3(_endpoint, _address) => { - todo!() +impl Config { + /// Creates a signer from given config. + pub fn signer_from_config(c: Config) -> Result { + // TODO: check chain id to select signer + match c { + Config::PrivateKey(key) => key + .parse::() + .map_err(|_| SignerError::InvalidPrivateKey), + Config::Keystore(path, password) => { + let keypath = Path::new(&path); + let private_key = + decrypt_key(&keypath, password).map_err(|_| SignerError::InvalidPassword)?; + PrivateKeySigner::from_slice(&private_key) + .map_err(|_| SignerError::InvalidPrivateKey) + } + Config::Web3(_endpoint, _address) => { + todo!() + } } } } #[cfg(test)] mod test { - use super::{signer_from_config, Config}; + use super::Config; use alloy_consensus::TxLegacy; use alloy_network::TxSignerSync; use alloy_primitives::{address, bytes, U256}; @@ -68,7 +71,7 @@ mod test { chain_id: Some(1), }; - let signer = signer_from_config(config); + let signer = Config::signer_from_config(config); let signature = signer.unwrap().sign_transaction_sync(&mut tx).unwrap(); let expected_signature = Signature::from_rs_and_parity( @@ -105,7 +108,7 @@ mod test { let expected_signer = PrivateKeySigner::from_slice(&private_key).unwrap(); let expected_signature = expected_signer.sign_transaction_sync(&mut tx).unwrap(); - let signer = signer_from_config(config); + let signer = Config::signer_from_config(config); let signature = signer.unwrap().sign_transaction_sync(&mut tx).unwrap(); assert_eq!(signature, expected_signature); From 2540943eaff4583d9f4a96b7ad42ded2626a6a43 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Wed, 24 Jul 2024 18:48:28 -0300 Subject: [PATCH 07/82] lint --- crates/signer/src/signer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 1850bc10..620b8e39 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -34,7 +34,7 @@ impl Config { Config::Keystore(path, password) => { let keypath = Path::new(&path); let private_key = - decrypt_key(&keypath, password).map_err(|_| SignerError::InvalidPassword)?; + decrypt_key(keypath, password).map_err(|_| SignerError::InvalidPassword)?; PrivateKeySigner::from_slice(&private_key) .map_err(|_| SignerError::InvalidPrivateKey) } From 473c20b659a6fed3e31b6287330057c702f80797 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 24 Jul 2024 18:53:29 -0300 Subject: [PATCH 08/82] skeleton for tx manager crate --- Cargo.lock | 4 ++ Cargo.toml | 107 ++++++++++++++-------------- crates/chainio/txmanager/Cargo.toml | 11 +++ crates/chainio/txmanager/README.md | 1 + crates/chainio/txmanager/src/lib.rs | 9 +++ 5 files changed, 80 insertions(+), 52 deletions(-) create mode 100644 crates/chainio/txmanager/Cargo.toml create mode 100644 crates/chainio/txmanager/README.md create mode 100644 crates/chainio/txmanager/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 8d18f687..13367a51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1344,6 +1344,10 @@ dependencies = [ "spki", ] +[[package]] +name = "eigen-chainio-txmanager" +version = "0.0.1-alpha" + [[package]] name = "eigen-chainio-utils" version = "0.0.1-alpha" diff --git a/Cargo.toml b/Cargo.toml index 89b036bc..0c4fcc68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,28 +1,30 @@ [workspace] -members = [ "crates/chainio/clients/avsregistry/", -"crates/chainio/clients/elcontracts/", -"crates/chainio/clients/eth/", -"crates/chainio/clients/fireblocks/", -"crates/contracts/bindings/", -"crates/chainio/utils/", -"crates/crypto/bn254/", -"crates/utils/", -"crates/crypto/bls/", -"crates/crypto/keystore/", -"crates/metrics/collectors/economic/", -"crates/metrics/collectors/rpc_calls/", -"crates/services/avsregistry/", -"crates/services/bls_aggregation/", -"crates/metrics/metrics-derive", -"crates/services/operatorsinfo/", -"crates/types/", -"crates/metrics/", -"crates/types/", -"examples/info-operator-service/", -"testing/testing-utils/", -"examples/avsregistry-read", -"examples/avsregistry-write", -"examples/anvil-utils" +members = [ + "crates/chainio/clients/avsregistry/", + "crates/chainio/clients/elcontracts/", + "crates/chainio/clients/eth/", + "crates/chainio/clients/fireblocks/", + "crates/contracts/bindings/", + "crates/chainio/txmanager/", + "crates/chainio/utils/", + "crates/crypto/bn254/", + "crates/utils/", + "crates/crypto/bls/", + "crates/crypto/keystore/", + "crates/metrics/collectors/economic/", + "crates/metrics/collectors/rpc_calls/", + "crates/services/avsregistry/", + "crates/services/bls_aggregation/", + "crates/metrics/metrics-derive", + "crates/services/operatorsinfo/", + "crates/types/", + "crates/metrics/", + "crates/types/", + "examples/info-operator-service/", + "testing/testing-utils/", + "examples/avsregistry-read", + "examples/avsregistry-write", + "examples/anvil-utils", ] resolver = "2" @@ -48,7 +50,7 @@ rustdoc.all = "warn" [workspace.dependencies] metrics-exporter-prometheus = "0.12.0" -ethers = "2.0.14" +ethers = "2.0.14" ark-ff = "0.4.0" eyre = "0.6.12" syn = "2.0" @@ -56,31 +58,32 @@ quote = "1.0" metrics = "0.21.1" once_cell = "1.17" reqwest = "0.12.4" -reth = {git = "https://github.com/paradigmxyz/reth"} +reth = { git = "https://github.com/paradigmxyz/reth" } prometheus-client = "0.22.2" -bn254 = {git = "https://github.com/sedaprotocol/bn254"} -eigen-metrics = {version = "0.0.1-alpha", path = "crates/metrics/"} -serde = {version = "1.0.197" , features = ["derive"]} -eigen-chainio-utils = {path = "crates/chainio/utils/"} -eigen-client-avsregistry = {path = "crates/chainio/clients/avsregistry"} -eigen-client-elcontracts = {path = "crates/chainio/clients/elcontracts"} -eigen-client-eth = {path = "crates/chainio/clients/eth"} -eigen-client-fireblocks = {path = "crates/chainio/clients/fireblocks"} -eigen-contract-bindings = { path = "crates/contracts/bindings/"} -eigen-types = {path = "crates/types/"} -eigen-crypto-bls = {path = "crates/crypto/bls/"} -eigen-crypto-bn254 = {path = "crates/crypto/bn254/"} -eigen-crypto-keystore = {path = "crates/crypto/keystore/"} -eigen-utils = {path = "crates/utils/"} -eigen-metrics-collectors-economic = {path = "crates/metrics/collectors/economic"} -eigen-metrics-collectors-rpc-calls = {path = "crates/metrics/collectors/rpc_calls"} -eigen-services-avsregistry = {path = "crates/services/avsregistry"} -eigen-services-bls_aggregation = {path = "crates/services/bls_aggregation"} -eigen-services-operatorsinfo = {path = "crates/services/operatorsinfo"} -eigen-metrics-derive = {path = "crates/metrics/metrics-derive"} -eigen-testing-utils = {path = "testing/testing-utils"} -info-operator-service = {path = "examples/info-operator-service"} -tokio = {version = "1.37.0" , features = ["test-util", "full","sync"] } +bn254 = { git = "https://github.com/sedaprotocol/bn254" } +eigen-metrics = { version = "0.0.1-alpha", path = "crates/metrics/" } +serde = { version = "1.0.197", features = ["derive"] } +eigen-chainio-utils = { path = "crates/chainio/utils/" } +eigen-chainio-txmanager = { path = "crates/chainio/txmanager/" } +eigen-client-avsregistry = { path = "crates/chainio/clients/avsregistry" } +eigen-client-elcontracts = { path = "crates/chainio/clients/elcontracts" } +eigen-client-eth = { path = "crates/chainio/clients/eth" } +eigen-client-fireblocks = { path = "crates/chainio/clients/fireblocks" } +eigen-contract-bindings = { path = "crates/contracts/bindings/" } +eigen-types = { path = "crates/types/" } +eigen-crypto-bls = { path = "crates/crypto/bls/" } +eigen-crypto-bn254 = { path = "crates/crypto/bn254/" } +eigen-crypto-keystore = { path = "crates/crypto/keystore/" } +eigen-utils = { path = "crates/utils/" } +eigen-metrics-collectors-economic = { path = "crates/metrics/collectors/economic" } +eigen-metrics-collectors-rpc-calls = { path = "crates/metrics/collectors/rpc_calls" } +eigen-services-avsregistry = { path = "crates/services/avsregistry" } +eigen-services-bls_aggregation = { path = "crates/services/bls_aggregation" } +eigen-services-operatorsinfo = { path = "crates/services/operatorsinfo" } +eigen-metrics-derive = { path = "crates/metrics/metrics-derive" } +eigen-testing-utils = { path = "testing/testing-utils" } +info-operator-service = { path = "examples/info-operator-service" } +tokio = { version = "1.37.0", features = ["test-util", "full", "sync"] } futures-util = "0.3.30" thiserror = "1.0" tracing = "0.1.40" @@ -130,6 +133,6 @@ alloy-rpc-client = { version = "0.1", default-features = false } alloy-contract = { version = "0.1", default-features = false } # examples -avsregistry-read = {path = "examples/avsregistry-read"} -avsregistry-write = {path = "examples/avsregistry-write"} -anvil-utils = {path = "examples/anvil-utils"} +avsregistry-read = { path = "examples/avsregistry-read" } +avsregistry-write = { path = "examples/avsregistry-write" } +anvil-utils = { path = "examples/anvil-utils" } diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml new file mode 100644 index 00000000..cccbfe0a --- /dev/null +++ b/crates/chainio/txmanager/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "eigen-chainio-txmanager" +description = "Eigen Layer Tx Manager" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +repository.workspace = true +license-file.workspace = true + +[dependencies] diff --git a/crates/chainio/txmanager/README.md b/crates/chainio/txmanager/README.md new file mode 100644 index 00000000..5070707b --- /dev/null +++ b/crates/chainio/txmanager/README.md @@ -0,0 +1 @@ +# Eigen SDK ChainIo Tx Manager diff --git a/crates/chainio/txmanager/src/lib.rs b/crates/chainio/txmanager/src/lib.rs new file mode 100644 index 00000000..06da3fcd --- /dev/null +++ b/crates/chainio/txmanager/src/lib.rs @@ -0,0 +1,9 @@ +#![doc( + html_logo_url = "https://github.com/supernovahs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", + issue_tracker_base_url = "https://github.com/supernovahs/eigen-rs/issues/" +)] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +pub fn println_hello() { + println!("Hello, world!"); +} From 5e528ada2cbbf442e7becc6540aa76ece23cd785 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 24 Jul 2024 19:15:58 -0300 Subject: [PATCH 09/82] skeleton for SimpleTxManager --- crates/chainio/txmanager/src/lib.rs | 2 ++ .../txmanager/src/simple_tx_manager.rs | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 crates/chainio/txmanager/src/simple_tx_manager.rs diff --git a/crates/chainio/txmanager/src/lib.rs b/crates/chainio/txmanager/src/lib.rs index 06da3fcd..440f4161 100644 --- a/crates/chainio/txmanager/src/lib.rs +++ b/crates/chainio/txmanager/src/lib.rs @@ -4,6 +4,8 @@ )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] +pub mod simple_tx_manager; + pub fn println_hello() { println!("Hello, world!"); } diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs new file mode 100644 index 00000000..4d71f4b6 --- /dev/null +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -0,0 +1,24 @@ +/* +type SimpleTxManager struct { + wallet wallet.Wallet + client eth.Client + log logging.Logger + sender common.Address + gasLimitMultiplier float64 +} +*/ + +// TODO!!! + +//use alloy_signer_local::PrivateKeySigner; +//use eth_keystore::decrypt_key; +//use std::path::Path; +// +// +//pub struct SimpleTxManager { +// wallet: wallet::Wallet, +// client: eth::Client, +// log: logging::Logger, +// sender: common::Address, +// gas_limit_multiplier: f64, +//} From 7aa052869af0d3a1af60f3736a5da99e43b5c9b1 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Thu, 25 Jul 2024 11:40:04 -0300 Subject: [PATCH 10/82] update cargo toml --- Cargo.toml | 5 +++-- crates/signer/Cargo.toml | 3 --- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1a7ee686..e5e7f4a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,12 +18,13 @@ members = [ "crates/chainio/clients/avsregistry/", "crates/types/", "crates/metrics/", "crates/types/", +"crates/signer/", "examples/info-operator-service/", "testing/testing-utils/", "examples/avsregistry-read", "examples/avsregistry-write", -"examples/anvil-utils" -, "crates/signer"] +"examples/anvil-utils", +] resolver = "2" diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index af69db7f..67d3e48a 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -16,6 +16,3 @@ eth-keystore = "0.5.0" hex-literal = "0.4.1" k256 = "0.13.3" thiserror.workspace = true - -[lints] -workspace = true From 53fe05db60c03336385707bcd55cf9163c664eb7 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Thu, 25 Jul 2024 12:01:52 -0300 Subject: [PATCH 11/82] fix cargo toml --- Cargo.toml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index e5e7f4a8..3490efb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,13 +57,21 @@ quote = "1.0" metrics = "0.21.1" once_cell = "1.17" reqwest = "0.12.4" +reth = {git = "https://github.com/paradigmxyz/reth"} +prometheus-client = "0.22.2" +bn254 = {git = "https://github.com/sedaprotocol/bn254"} +eigen-metrics = {version = "0.0.1-alpha", path = "crates/metrics/"} serde = {version = "1.0.197" , features = ["derive"]} eigen-chainio-utils = {path = "crates/chainio/utils/"} eigen-client-avsregistry = {path = "crates/chainio/clients/avsregistry"} eigen-client-elcontracts = {path = "crates/chainio/clients/elcontracts"} +eigen-client-eth = {path = "crates/chainio/clients/eth"} +eigen-client-fireblocks = {path = "crates/chainio/clients/fireblocks"} +eigen-contract-bindings = { path = "crates/contracts/bindings/"} eigen-types = {path = "crates/types/"} eigen-crypto-bls = {path = "crates/crypto/bls/"} eigen-crypto-bn254 = {path = "crates/crypto/bn254/"} +eigen-crypto-keystore = {path = "crates/crypto/keystore/"} eigen-utils = {path = "crates/utils/"} eigen-metrics-collectors-economic = {path = "crates/metrics/collectors/economic"} eigen-services-avsregistry = {path = "crates/services/avsregistry"} @@ -79,11 +87,27 @@ hyper = "0.14.25" #misc parking_lot = "0.12" + +#alloy +alloy-chains = "0.1.15" alloy-primitives = "0.7.2" +alloy-dyn-abi = "0.7.2" alloy-sol-types = "0.7.2" +alloy-rlp = "0.3.4" +alloy-trie = "0.4" alloy-rpc-types = { version = "0.1", default-features = false, features = [ "eth", ] } +alloy-rpc-types-anvil = { version = "0.1", default-features = false } +alloy-rpc-types-beacon = { version = "0.1", default-features = false } +alloy-rpc-types-admin = { version = "0.1", default-features = false } +alloy-rpc-types-txpool = { version = "0.1", default-features = false } +alloy-serde = { version = "0.1", default-features = false } +alloy-rpc-types-engine = { version = "0.1", default-features = false } +alloy-rpc-types-eth = { version = "0.1", default-features = false } +alloy-rpc-types-trace = { version = "0.1", default-features = false } +alloy-genesis = { version = "0.1", default-features = false } +alloy-node-bindings = { version = "0.1", default-features = false } alloy-provider = { version = "0.1", default-features = false, features = [ "reqwest", ] } @@ -91,7 +115,19 @@ alloy-eips = { version = "0.1", default-features = false } alloy-signer = { version = "0.1", default-features = false } alloy-signer-local = { version = "0.1", default-features = false } alloy-network = { version = "0.1", default-features = false } +alloy-consensus = { version = "0.1", default-features = false } +alloy-transport = { version = "0.1" } alloy-transport-http = { version = "0.1", features = [ "reqwest-rustls-tls", ], default-features = false } +alloy-transport-ws = { version = "0.1", default-features = false } +alloy-transport-ipc = { version = "0.1", default-features = false } +alloy-pubsub = { version = "0.1", default-features = false } +alloy-json-rpc = { version = "0.1", default-features = false } +alloy-rpc-client = { version = "0.1", default-features = false } alloy-contract = { version = "0.1", default-features = false } + +# examples +avsregistry-read = {path = "examples/avsregistry-read"} +avsregistry-write = {path = "examples/avsregistry-write"} +anvil-utils = {path = "examples/anvil-utils"} \ No newline at end of file From 8b00a5649975bcc590ab1a9b40ba9aed28b80b87 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Thu, 25 Jul 2024 12:34:06 -0300 Subject: [PATCH 12/82] update cargo toml --- Cargo.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3490efb1..2d9139f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,11 +19,12 @@ members = [ "crates/chainio/clients/avsregistry/", "crates/metrics/", "crates/types/", "crates/signer/", + "examples/info-operator-service/", "testing/testing-utils/", "examples/avsregistry-read", "examples/avsregistry-write", -"examples/anvil-utils", +"examples/anvil-utils" ] resolver = "2" @@ -74,10 +75,13 @@ eigen-crypto-bn254 = {path = "crates/crypto/bn254/"} eigen-crypto-keystore = {path = "crates/crypto/keystore/"} eigen-utils = {path = "crates/utils/"} eigen-metrics-collectors-economic = {path = "crates/metrics/collectors/economic"} +eigen-metrics-collectors-rpc-calls = {path = "crates/metrics/collectors/rpc_calls"} eigen-services-avsregistry = {path = "crates/services/avsregistry"} +eigen-services-bls_aggregation = {path = "crates/services/bls_aggregation"} eigen-services-operatorsinfo = {path = "crates/services/operatorsinfo"} eigen-metrics-derive = {path = "crates/metrics/metrics-derive"} eigen-testing-utils = {path = "testing/testing-utils"} +info-operator-service = {path = "examples/info-operator-service"} tokio = {version = "1.37.0" , features = ["test-util", "full","sync"] } futures-util = "0.3.30" thiserror = "1.0" @@ -130,4 +134,4 @@ alloy-contract = { version = "0.1", default-features = false } # examples avsregistry-read = {path = "examples/avsregistry-read"} avsregistry-write = {path = "examples/avsregistry-write"} -anvil-utils = {path = "examples/anvil-utils"} \ No newline at end of file +anvil-utils = {path = "examples/anvil-utils"} From 7d1d0a70efccf19ec0675d338d90df95b0b96974 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Thu, 25 Jul 2024 12:34:31 -0300 Subject: [PATCH 13/82] update cargo toml --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2d9139f1..2b9d36bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ members = [ "crates/chainio/clients/avsregistry/", "crates/metrics/", "crates/types/", "crates/signer/", - "examples/info-operator-service/", "testing/testing-utils/", "examples/avsregistry-read", From b18e85e68d9137f38e3855813fdb1484bea1423a Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Thu, 25 Jul 2024 15:43:42 -0300 Subject: [PATCH 14/82] update comments --- crates/signer/src/signer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 620b8e39..7e1e8e0e 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -15,7 +15,7 @@ pub enum Config { } #[derive(Error, Debug)] -#[allow(missing_docs)] +/// Possible errors raised in signer creation pub enum SignerError { #[error("invalid private key")] InvalidPrivateKey, @@ -39,7 +39,7 @@ impl Config { .map_err(|_| SignerError::InvalidPrivateKey) } Config::Web3(_endpoint, _address) => { - todo!() + todo!() // We are implementing this in a following PR } } } From 3deffbf97d5c35964d33e01613aba4a355ca9e52 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Thu, 25 Jul 2024 16:00:58 -0300 Subject: [PATCH 15/82] add aws signer getter function --- crates/signer/Cargo.toml | 7 ++++-- crates/signer/src/signer.rs | 48 ++++++++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index af69db7f..d2e2edfc 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -7,15 +7,18 @@ repository.workspace = true [dependencies] alloy-consensus = "0.2.0" -alloy-contract = "0.2.0" alloy-network = "0.2.0" alloy-primitives = "0.7.7" alloy-signer.workspace = true +alloy-signer-aws = "0.2.0" alloy-signer-local = "0.2.0" +aws-config = "1.5.4" +aws-sdk-kms = "1.37.0" eth-keystore = "0.5.0" +ethers-signers = "2.0.14" hex-literal = "0.4.1" -k256 = "0.13.3" thiserror.workspace = true +tokio.workspace = true [lints] workspace = true diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 620b8e39..5ddb7259 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -1,4 +1,7 @@ +use alloy_signer_aws::AwsSigner; use alloy_signer_local::PrivateKeySigner; +use aws_config::{BehaviorVersion, Region}; +use aws_sdk_kms; use eth_keystore::decrypt_key; use std::path::Path; use thiserror::Error; @@ -43,17 +46,29 @@ impl Config { } } } + /// Creates a signer from a key ID in AWS Key Management Service + pub async fn aws_signer(key_id: String, region: Region) -> AwsSigner { + let config = aws_config::load_defaults(BehaviorVersion::latest()) + .await + .to_builder() + .region(Some(region)) + .build(); + let client = aws_sdk_kms::Client::new(&config); + let chain_id = Some(1); + AwsSigner::new(client, key_id, chain_id).await.unwrap() + } } #[cfg(test)] mod test { use super::Config; - use alloy_consensus::TxLegacy; - use alloy_network::TxSignerSync; + use super::*; + use alloy_consensus::{SignableTransaction, TxLegacy}; + use alloy_network::{TxSigner, TxSignerSync}; + use alloy_primitives::hex_literal::hex; use alloy_primitives::{address, bytes, U256}; use alloy_signer::Signature; use alloy_signer_local::PrivateKeySigner; - use hex_literal::hex; use std::str::FromStr; #[test] @@ -113,4 +128,31 @@ mod test { assert_eq!(signature, expected_signature); } + + #[tokio::test] + async fn sign_transaction_with_aws_signer() { + let key_id = "1234abcd-12ab-34cd-56ef-1234567890ab".to_string(); + let region = Region::from_static("us-west-2a"); + let signer = Config::aws_signer(key_id, region).await; + let mut tx = TxLegacy { + to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), + value: U256::from(1_000_000_000), + gas_limit: 2_000_000, + nonce: 0, + gas_price: 21_000_000_000, + input: bytes!(), + chain_id: Some(1), + }; + + // This request fails because key_id is not a valid key + let sig = signer.sign_transaction(&mut tx).await.unwrap(); + + let mut encoded_tx = Vec::new(); + tx.encode_for_signing(&mut encoded_tx); + + assert_eq!( + sig.recover_address_from_msg(encoded_tx).unwrap(), + signer.address() + ); + } } From 2618ac53e79b7b502f95392ba95905b454730d51 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Thu, 25 Jul 2024 16:22:55 -0300 Subject: [PATCH 16/82] change aws_signer function so that it receives chain_id as argument --- crates/signer/src/signer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index ba4d3e11..2494e6c7 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -47,14 +47,13 @@ impl Config { } } /// Creates a signer from a key ID in AWS Key Management Service - pub async fn aws_signer(key_id: String, region: Region) -> AwsSigner { + pub async fn aws_signer(key_id: String, chain_id: Option, region: Region) -> AwsSigner { let config = aws_config::load_defaults(BehaviorVersion::latest()) .await .to_builder() .region(Some(region)) .build(); let client = aws_sdk_kms::Client::new(&config); - let chain_id = Some(1); AwsSigner::new(client, key_id, chain_id).await.unwrap() } } @@ -132,8 +131,9 @@ mod test { #[tokio::test] async fn sign_transaction_with_aws_signer() { let key_id = "1234abcd-12ab-34cd-56ef-1234567890ab".to_string(); + let chain_id = Some(1); let region = Region::from_static("us-west-2a"); - let signer = Config::aws_signer(key_id, region).await; + let signer = Config::aws_signer(key_id, chain_id, region).await; let mut tx = TxLegacy { to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), value: U256::from(1_000_000_000), From 17fd5d70323948a71b2d05eeb7c771a2b6f4864e Mon Sep 17 00:00:00 2001 From: ricomateo Date: Thu, 25 Jul 2024 16:26:37 -0300 Subject: [PATCH 17/82] add error handling --- crates/signer/src/signer.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 2494e6c7..2b17fc5e 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -1,4 +1,4 @@ -use alloy_signer_aws::AwsSigner; +use alloy_signer_aws::{AwsSigner, AwsSignerError}; use alloy_signer_local::PrivateKeySigner; use aws_config::{BehaviorVersion, Region}; use aws_sdk_kms; @@ -47,14 +47,18 @@ impl Config { } } /// Creates a signer from a key ID in AWS Key Management Service - pub async fn aws_signer(key_id: String, chain_id: Option, region: Region) -> AwsSigner { + pub async fn aws_signer( + key_id: String, + chain_id: Option, + region: Region, + ) -> Result { let config = aws_config::load_defaults(BehaviorVersion::latest()) .await .to_builder() .region(Some(region)) .build(); let client = aws_sdk_kms::Client::new(&config); - AwsSigner::new(client, key_id, chain_id).await.unwrap() + Ok(AwsSigner::new(client, key_id, chain_id).await?) } } @@ -133,7 +137,7 @@ mod test { let key_id = "1234abcd-12ab-34cd-56ef-1234567890ab".to_string(); let chain_id = Some(1); let region = Region::from_static("us-west-2a"); - let signer = Config::aws_signer(key_id, chain_id, region).await; + let signer = Config::aws_signer(key_id, chain_id, region).await.unwrap(); let mut tx = TxLegacy { to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), value: U256::from(1_000_000_000), From b4c2804bc1c32dac66d90e00d32cb934c4e38576 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 25 Jul 2024 16:54:51 -0300 Subject: [PATCH 18/82] progress in SimpleTxManager --- Cargo.lock | 4 ++ crates/chainio/txmanager/Cargo.toml | 2 + .../txmanager/src/simple_tx_manager.rs | 51 +++++++++++++------ 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13367a51..34ac93ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1347,6 +1347,10 @@ dependencies = [ [[package]] name = "eigen-chainio-txmanager" version = "0.0.1-alpha" +dependencies = [ + "alloy-network", + "alloy-primitives", +] [[package]] name = "eigen-chainio-utils" diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index cccbfe0a..03f6525a 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -9,3 +9,5 @@ repository.workspace = true license-file.workspace = true [dependencies] +alloy-network.workspace = true +alloy-primitives.workspace = true diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 4d71f4b6..78f731af 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -1,12 +1,7 @@ -/* -type SimpleTxManager struct { - wallet wallet.Wallet - client eth.Client - log logging.Logger - sender common.Address - gasLimitMultiplier float64 -} -*/ +use alloy_network::{Ethereum, EthereumWallet}; +use alloy_primitives::{address, fixed_bytes, Address, Bytes, FixedBytes, B256, I256, U256}; +//use alloy_provider::Provider; +//use alloy_rpc_types::Filter; // TODO!!! @@ -15,10 +10,34 @@ type SimpleTxManager struct { //use std::path::Path; // // -//pub struct SimpleTxManager { -// wallet: wallet::Wallet, -// client: eth::Client, -// log: logging::Logger, -// sender: common::Address, -// gas_limit_multiplier: f64, -//} +pub struct SimpleTxManager { + wallet: EthereumWallet, + // client: eth::Client, + // log: logging::Logger, + sender: Address, + gas_limit_multiplier: f64, +} + +impl SimpleTxManager { + /* + pub fn new( + wallet: wallet::Wallet, + client: eth::Client, + log: logging::Logger, + sender: common::Address, + gas_limit_multiplier: f64, + ) -> SimpleTxManager { + SimpleTxManager { + wallet, + client, + log, + sender, + gas_limit_multiplier, + } + } + */ + + pub fn with_gas_limit_multiplier(&mut self, multiplier: f64) { + self.gas_limit_multiplier = multiplier; + } +} From 6c09f5b9aac00d2004b42e6f3e283613e9ee26e7 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Fri, 26 Jul 2024 10:22:30 -0300 Subject: [PATCH 19/82] change str literals for constants --- crates/signer/src/signer.rs | 38 ++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 7e1e8e0e..0c44d353 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -3,8 +3,8 @@ use eth_keystore::decrypt_key; use std::path::Path; use thiserror::Error; -#[derive(Debug)] /// Represents the input params to create a signer +#[derive(Debug)] pub enum Config { /// Hexadecimal private key PrivateKey(String), @@ -50,19 +50,27 @@ mod test { use super::Config; use alloy_consensus::TxLegacy; use alloy_network::TxSignerSync; - use alloy_primitives::{address, bytes, U256}; + use alloy_primitives::{bytes, Address, U256}; use alloy_signer::Signature; use alloy_signer_local::PrivateKeySigner; use hex_literal::hex; use std::str::FromStr; + const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; + const ADDRESS: [u8; 20] = hex!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + const SIGNATURE_R: &str = + "99963972037857174861280476053118856715670512199525969754644366601434507134123"; + const SIGNATURE_S: &str = + "54587766196536123534774489028213321677166972433316011091332824361042811624091"; + const SIGNATURE_Y_PARITY: u64 = 37; + const KEYSTORE_PATH: &str = "mockdata/dummy.key.json"; + const KEYSTORE_PASSWORD: &str = "testpassword"; + #[test] fn sign_transaction_with_private_key() { - let private_key = - "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7".to_owned(); - let config = Config::PrivateKey(private_key); + let config = Config::PrivateKey(PRIVATE_KEY.into()); let mut tx = TxLegacy { - to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), + to: Address::from(ADDRESS).into(), value: U256::from(1_000_000_000), gas_limit: 2_000_000, nonce: 0, @@ -75,15 +83,9 @@ mod test { let signature = signer.unwrap().sign_transaction_sync(&mut tx).unwrap(); let expected_signature = Signature::from_rs_and_parity( - U256::from_str( - "99963972037857174861280476053118856715670512199525969754644366601434507134123", - ) - .unwrap(), - U256::from_str( - "54587766196536123534774489028213321677166972433316011091332824361042811624091", - ) - .unwrap(), - 37, + U256::from_str(SIGNATURE_R).unwrap(), + U256::from_str(SIGNATURE_S).unwrap(), + SIGNATURE_Y_PARITY, ) .unwrap(); assert_eq!(signature, expected_signature); @@ -91,11 +93,9 @@ mod test { #[test] fn sign_transaction_with_keystore() { - let path = "mockdata/dummy.key.json".to_owned(); - let password = "testpassword".to_owned(); - let config = Config::Keystore(path, password); + let config = Config::Keystore(KEYSTORE_PATH.into(), KEYSTORE_PASSWORD.into()); let mut tx = TxLegacy { - to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), + to: Address::from(ADDRESS).into(), value: U256::from(1_000_000_000), gas_limit: 2_000_000, nonce: 0, From e045b5605d3d7dbc9d424e3808b6a63aceca306c Mon Sep 17 00:00:00 2001 From: ricomateo Date: Fri, 26 Jul 2024 17:14:02 -0300 Subject: [PATCH 20/82] organize Cargo.toml to avoid duplicates and unused dependencies --- Cargo.lock | 212 +++++++++------------------------------ Cargo.toml | 10 +- crates/signer/Cargo.toml | 19 ++-- 3 files changed, 62 insertions(+), 179 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7fb0d3d3..c68a996d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,24 +81,10 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a016bfa21193744d4c38b3f3ab845462284d129e5e23c7cc0fafca7e92d9db37" dependencies = [ - "alloy-eips 0.1.2", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.1.2", - "c-kzg", - "serde", -] - -[[package]] -name = "alloy-consensus" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58047cc851e58c26224521d1ecda466e3d746ebca0274cd5427aa660a88c353" -dependencies = [ - "alloy-eips 0.2.0", - "alloy-primitives", - "alloy-rlp", - "alloy-serde 0.2.0", + "alloy-serde", "c-kzg", "serde", ] @@ -111,10 +97,10 @@ checksum = "e47b2a620fd588d463ccf0f5931b41357664b293a8d31592768845a2a101bb9e" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", - "alloy-network 0.1.2", + "alloy-network", "alloy-primitives", "alloy-provider", - "alloy-rpc-types-eth 0.1.2", + "alloy-rpc-types-eth", "alloy-sol-types", "alloy-transport", "futures", @@ -147,22 +133,7 @@ checksum = "32d6d8118b83b0489cfb7e6435106948add2b35217f4a5004ef895f613f60299" dependencies = [ "alloy-primitives", "alloy-rlp", - "alloy-serde 0.1.2", - "c-kzg", - "once_cell", - "serde", - "sha2", -] - -[[package]] -name = "alloy-eips" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a3e14fa0d152d00bd8daf605eb74ad397efb0f54bd7155585823dddb4401e" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "alloy-serde 0.2.0", + "alloy-serde", "c-kzg", "once_cell", "serde", @@ -194,52 +165,19 @@ dependencies = [ "tracing", ] -[[package]] -name = "alloy-json-rpc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e76a9feec2352c78545d1a37415699817bae8dc41654bd1bfe57d6cdd5433bd" -dependencies = [ - "alloy-primitives", - "serde", - "serde_json", - "thiserror", - "tracing", -] - [[package]] name = "alloy-network" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc122cbee2b8523854cc11d87bcd5773741602c553d2d2d106d82eeb9c16924a" dependencies = [ - "alloy-consensus 0.1.2", - "alloy-eips 0.1.2", - "alloy-json-rpc 0.1.2", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", "alloy-primitives", - "alloy-rpc-types-eth 0.1.2", - "alloy-serde 0.1.2", - "alloy-signer 0.1.2", - "alloy-sol-types", - "async-trait", - "auto_impl", - "futures-utils-wasm", - "thiserror", -] - -[[package]] -name = "alloy-network" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3223d71dc78f464b2743418d0be8b5c894313e272105a6206ad5e867d67b3ce2" -dependencies = [ - "alloy-consensus 0.2.0", - "alloy-eips 0.2.0", - "alloy-json-rpc 0.2.0", - "alloy-primitives", - "alloy-rpc-types-eth 0.2.0", - "alloy-serde 0.2.0", - "alloy-signer 0.2.0", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", "alloy-sol-types", "async-trait", "auto_impl", @@ -276,14 +214,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d5af289798fe8783acd0c5f10644d9d26f54a12bc52a083e4f3b31718e9bf92" dependencies = [ "alloy-chains", - "alloy-consensus 0.1.2", - "alloy-eips 0.1.2", - "alloy-json-rpc 0.1.2", - "alloy-network 0.1.2", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", "alloy-primitives", "alloy-pubsub", "alloy-rpc-client", - "alloy-rpc-types-eth 0.1.2", + "alloy-rpc-types-eth", "alloy-transport", "alloy-transport-http", "alloy-transport-ws", @@ -309,7 +247,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702f330b7da123a71465ab9d39616292f8344a2811c28f2cc8d8438a69d79e35" dependencies = [ - "alloy-json-rpc 0.1.2", + "alloy-json-rpc", "alloy-primitives", "alloy-transport", "bimap", @@ -350,7 +288,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b40fcb53b2a9d0a78a4968b2eca8805a4b7011b9ee3fdfa2acaf137c5128f36b" dependencies = [ - "alloy-json-rpc 0.1.2", + "alloy-json-rpc", "alloy-primitives", "alloy-pubsub", "alloy-transport", @@ -374,8 +312,8 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50f2fbe956a3e0f0975c798f488dc6be96b669544df3737e18f4a325b42f4c86" dependencies = [ - "alloy-rpc-types-eth 0.1.2", - "alloy-serde 0.1.2", + "alloy-rpc-types-eth", + "alloy-serde", ] [[package]] @@ -384,29 +322,11 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "083f443a83b9313373817236a8f4bea09cca862618e9177d822aee579640a5d6" dependencies = [ - "alloy-consensus 0.1.2", - "alloy-eips 0.1.2", + "alloy-consensus", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.1.2", - "alloy-sol-types", - "itertools 0.13.0", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "alloy-rpc-types-eth" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "605fa8462732bb8fd0645a9941e12961e079d45ae6a44634c826f8229c187bdf" -dependencies = [ - "alloy-consensus 0.2.0", - "alloy-eips 0.2.0", - "alloy-primitives", - "alloy-rlp", - "alloy-serde 0.2.0", + "alloy-serde", "alloy-sol-types", "itertools 0.13.0", "serde", @@ -425,17 +345,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "alloy-serde" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c5b9057acc02aee1b8aac2b5a0729cb0f73d080082c111313e5d1f92a96630" -dependencies = [ - "alloy-primitives", - "serde", - "serde_json", -] - [[package]] name = "alloy-signer" version = "0.1.2" @@ -450,30 +359,16 @@ dependencies = [ "thiserror", ] -[[package]] -name = "alloy-signer" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37f10592696f4ab8b687d5a8ab55e998a14ea0ca5f8eb20ad74a96ad671bb54a" -dependencies = [ - "alloy-primitives", - "async-trait", - "auto_impl", - "elliptic-curve", - "k256", - "thiserror", -] - [[package]] name = "alloy-signer-aws" -version = "0.2.0" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49300a7aecbd28c364fbad6a9f886264f79ff4fed9a67c8caa27c39f99d52b2d" +checksum = "63ce17bfd5aa38e14b9c83b553d93c76e1bd5641a2db45f381f81619fd3e54ca" dependencies = [ - "alloy-consensus 0.2.0", - "alloy-network 0.2.0", + "alloy-consensus", + "alloy-network", "alloy-primitives", - "alloy-signer 0.2.0", + "alloy-signer", "async-trait", "aws-sdk-kms", "k256", @@ -488,26 +383,10 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d40a37dc216c269b8a7244047cb1c18a9c69f7a0332ab2c4c2aa4cbb1a31468b" dependencies = [ - "alloy-consensus 0.1.2", - "alloy-network 0.1.2", + "alloy-consensus", + "alloy-network", "alloy-primitives", - "alloy-signer 0.1.2", - "async-trait", - "k256", - "rand", - "thiserror", -] - -[[package]] -name = "alloy-signer-local" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b537f3e55f30753578f4623d5f66ddad8fa582af3fa6b15bad23dd1b9775228" -dependencies = [ - "alloy-consensus 0.2.0", - "alloy-network 0.2.0", - "alloy-primitives", - "alloy-signer 0.2.0", + "alloy-signer", "async-trait", "k256", "rand", @@ -593,7 +472,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245af9541f0a0dbd5258669c80dfe3af118164cacec978a520041fc130550deb" dependencies = [ - "alloy-json-rpc 0.1.2", + "alloy-json-rpc", "base64 0.22.1", "futures-util", "futures-utils-wasm", @@ -611,7 +490,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5619c017e1fdaa1db87f9182f4f0ed97c53d674957f4902fba655e972d359c6c" dependencies = [ - "alloy-json-rpc 0.1.2", + "alloy-json-rpc", "alloy-transport", "reqwest 0.12.5", "serde_json", @@ -1841,12 +1720,12 @@ name = "eigen-client-avsregistry" version = "0.0.1-alpha" dependencies = [ "alloy-contract", - "alloy-network 0.1.2", + "alloy-network", "alloy-primitives", "alloy-provider", "alloy-rpc-types", - "alloy-signer 0.1.2", - "alloy-signer-local 0.1.2", + "alloy-signer", + "alloy-signer-local", "alloy-transport-http", "ark-bn254", "ark-ff 0.4.2", @@ -1868,10 +1747,10 @@ name = "eigen-client-elcontracts" version = "0.0.1-alpha" dependencies = [ "alloy-contract", - "alloy-eips 0.1.2", + "alloy-eips", "alloy-primitives", "alloy-provider", - "alloy-signer-local 0.1.2", + "alloy-signer-local", "eigen-testing-utils", "eigen-types", "eigen-utils", @@ -2042,16 +1921,15 @@ dependencies = [ name = "eigen-signer" version = "0.0.1-alpha" dependencies = [ - "alloy-consensus 0.2.0", - "alloy-network 0.2.0", + "alloy-consensus", + "alloy-network", "alloy-primitives", - "alloy-signer 0.1.2", + "alloy-signer", "alloy-signer-aws", - "alloy-signer-local 0.2.0", + "alloy-signer-local", "aws-config", "aws-sdk-kms", "eth-keystore", - "ethers-signers", "hex-literal", "thiserror", "tokio", @@ -2061,7 +1939,7 @@ dependencies = [ name = "eigen-testing-utils" version = "0.0.1-alpha" dependencies = [ - "alloy-network 0.1.2", + "alloy-network", "alloy-primitives", "alloy-provider", "alloy-transport-http", @@ -2085,9 +1963,9 @@ name = "eigen-utils" version = "0.0.1-alpha" dependencies = [ "alloy-contract", - "alloy-network 0.1.2", + "alloy-network", "alloy-provider", - "alloy-signer-local 0.1.2", + "alloy-signer-local", "alloy-sol-types", "alloy-transport-http", "reqwest 0.12.5", diff --git a/Cargo.toml b/Cargo.toml index 0fee71d4..ca1db2b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ members = [ "testing/testing-utils/", "examples/avsregistry-read", "examples/avsregistry-write", - "examples/anvil-utils" + "examples/anvil-utils", ] resolver = "2" @@ -89,7 +89,11 @@ thiserror = "1.0" tracing = "0.1.40" tracing-subscriber = { version = "0.3", features = ["json"] } hyper = "0.14.25" - +hex-literal = "0.4.1" +ethers-signers = "2.0.14" +eth-keystore = "0.5.0" +aws-config = "1.5.4" +aws-sdk-kms = "1.37.0" #misc parking_lot = "0.12" @@ -132,6 +136,8 @@ alloy-pubsub = { version = "0.1", default-features = false } alloy-json-rpc = { version = "0.1", default-features = false } alloy-rpc-client = { version = "0.1", default-features = false } alloy-contract = { version = "0.1", default-features = false } +alloy-signer-aws = "0.1.0" + # examples avsregistry-read = { path = "examples/avsregistry-read" } diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index d2e2edfc..60b25821 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -6,17 +6,16 @@ rust-version.workspace = true repository.workspace = true [dependencies] -alloy-consensus = "0.2.0" -alloy-network = "0.2.0" -alloy-primitives = "0.7.7" +alloy-consensus.workspace = true +alloy-network.workspace = true +alloy-primitives.workspace = true alloy-signer.workspace = true -alloy-signer-aws = "0.2.0" -alloy-signer-local = "0.2.0" -aws-config = "1.5.4" -aws-sdk-kms = "1.37.0" -eth-keystore = "0.5.0" -ethers-signers = "2.0.14" -hex-literal = "0.4.1" +alloy-signer-aws.workspace = true +alloy-signer-local.workspace = true +aws-config.workspace = true +aws-sdk-kms.workspace = true +eth-keystore.workspace = true +hex-literal.workspace = true thiserror.workspace = true tokio.workspace = true From 5c0a1e2ece545df578888d5efc7ab46459eefdf4 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Fri, 26 Jul 2024 17:43:49 -0300 Subject: [PATCH 21/82] add web3 signer --- Cargo.lock | 107 +++++++++++++++++++++++++------ Cargo.toml | 3 +- crates/signer/Cargo.toml | 3 + crates/signer/src/lib.rs | 1 + crates/signer/src/signer.rs | 15 +++++ crates/signer/src/web3_signer.rs | 66 +++++++++++++++++++ 6 files changed, 176 insertions(+), 19 deletions(-) create mode 100644 crates/signer/src/web3_signer.rs diff --git a/Cargo.lock b/Cargo.lock index c68a996d..5cfeb20c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,7 +102,7 @@ dependencies = [ "alloy-provider", "alloy-rpc-types-eth", "alloy-sol-types", - "alloy-transport", + "alloy-transport 0.1.2", "futures", "futures-util", "thiserror", @@ -165,6 +165,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "alloy-json-rpc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e76a9feec2352c78545d1a37415699817bae8dc41654bd1bfe57d6cdd5433bd" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", + "thiserror", + "tracing", +] + [[package]] name = "alloy-network" version = "0.1.2" @@ -173,7 +186,7 @@ checksum = "dc122cbee2b8523854cc11d87bcd5773741602c553d2d2d106d82eeb9c16924a" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-json-rpc", + "alloy-json-rpc 0.1.2", "alloy-primitives", "alloy-rpc-types-eth", "alloy-serde", @@ -216,14 +229,14 @@ dependencies = [ "alloy-chains", "alloy-consensus", "alloy-eips", - "alloy-json-rpc", + "alloy-json-rpc 0.1.2", "alloy-network", "alloy-primitives", "alloy-pubsub", - "alloy-rpc-client", + "alloy-rpc-client 0.1.2", "alloy-rpc-types-eth", - "alloy-transport", - "alloy-transport-http", + "alloy-transport 0.1.2", + "alloy-transport-http 0.1.2", "alloy-transport-ws", "async-stream", "async-trait", @@ -247,9 +260,9 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702f330b7da123a71465ab9d39616292f8344a2811c28f2cc8d8438a69d79e35" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.1.2", "alloy-primitives", - "alloy-transport", + "alloy-transport 0.1.2", "bimap", "futures", "serde", @@ -288,11 +301,11 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b40fcb53b2a9d0a78a4968b2eca8805a4b7011b9ee3fdfa2acaf137c5128f36b" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.1.2", "alloy-primitives", "alloy-pubsub", - "alloy-transport", - "alloy-transport-http", + "alloy-transport 0.1.2", + "alloy-transport-http 0.1.2", "alloy-transport-ws", "futures", "pin-project", @@ -306,6 +319,27 @@ dependencies = [ "url", ] +[[package]] +name = "alloy-rpc-client" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a9e609524fa31c2c70eb24c0da60796809193ad4787a6dfe6d0db0d3ac112d" +dependencies = [ + "alloy-json-rpc 0.2.0", + "alloy-transport 0.2.0", + "alloy-transport-http 0.2.0", + "futures", + "pin-project", + "reqwest 0.12.5", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", + "url", +] + [[package]] name = "alloy-rpc-types" version = "0.1.2" @@ -472,7 +506,25 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245af9541f0a0dbd5258669c80dfe3af118164cacec978a520041fc130550deb" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.1.2", + "base64 0.22.1", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "url", +] + +[[package]] +name = "alloy-transport" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b44b0f6f4a2593b258fa7b6cae8968e6a4c404d9ef4f5bc74401f2d04fa23fa" +dependencies = [ + "alloy-json-rpc 0.2.0", "base64 0.22.1", "futures-util", "futures-utils-wasm", @@ -481,6 +533,7 @@ dependencies = [ "thiserror", "tokio", "tower", + "tracing", "url", ] @@ -490,8 +543,23 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5619c017e1fdaa1db87f9182f4f0ed97c53d674957f4902fba655e972d359c6c" dependencies = [ - "alloy-json-rpc", - "alloy-transport", + "alloy-json-rpc 0.1.2", + "alloy-transport 0.1.2", + "reqwest 0.12.5", + "serde_json", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-transport-http" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d8f1eefa8cb9e7550740ee330feba4fed303a77ad3085707546f9152a88c380" +dependencies = [ + "alloy-json-rpc 0.2.0", + "alloy-transport 0.2.0", "reqwest 0.12.5", "serde_json", "tower", @@ -506,7 +574,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c0aff8af5be5e58856c5cdd1e46db2c67c7ecd3a652d9100b4822c96c899947" dependencies = [ "alloy-pubsub", - "alloy-transport", + "alloy-transport 0.1.2", "futures", "http 1.1.0", "rustls 0.23.10", @@ -1726,7 +1794,7 @@ dependencies = [ "alloy-rpc-types", "alloy-signer", "alloy-signer-local", - "alloy-transport-http", + "alloy-transport-http 0.1.2", "ark-bn254", "ark-ff 0.4.2", "eigen-chainio-utils", @@ -1924,6 +1992,7 @@ dependencies = [ "alloy-consensus", "alloy-network", "alloy-primitives", + "alloy-rpc-client 0.2.0", "alloy-signer", "alloy-signer-aws", "alloy-signer-local", @@ -1931,8 +2000,10 @@ dependencies = [ "aws-sdk-kms", "eth-keystore", "hex-literal", + "serde", "thiserror", "tokio", + "url", ] [[package]] @@ -1942,7 +2013,7 @@ dependencies = [ "alloy-network", "alloy-primitives", "alloy-provider", - "alloy-transport-http", + "alloy-transport-http 0.1.2", "eigen-utils", "once_cell", ] @@ -1967,7 +2038,7 @@ dependencies = [ "alloy-provider", "alloy-signer-local", "alloy-sol-types", - "alloy-transport-http", + "alloy-transport-http 0.1.2", "reqwest 0.12.5", ] diff --git a/Cargo.toml b/Cargo.toml index ca1db2b6..430847ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,6 +94,7 @@ ethers-signers = "2.0.14" eth-keystore = "0.5.0" aws-config = "1.5.4" aws-sdk-kms = "1.37.0" +url = "2.5.2" #misc parking_lot = "0.12" @@ -134,7 +135,7 @@ alloy-transport-ws = { version = "0.1", default-features = false } alloy-transport-ipc = { version = "0.1", default-features = false } alloy-pubsub = { version = "0.1", default-features = false } alloy-json-rpc = { version = "0.1", default-features = false } -alloy-rpc-client = { version = "0.1", default-features = false } +alloy-rpc-client = "0.2" alloy-contract = { version = "0.1", default-features = false } alloy-signer-aws = "0.1.0" diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index 60b25821..7563edf2 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -12,12 +12,15 @@ alloy-primitives.workspace = true alloy-signer.workspace = true alloy-signer-aws.workspace = true alloy-signer-local.workspace = true +alloy-rpc-client.workspace = true aws-config.workspace = true aws-sdk-kms.workspace = true eth-keystore.workspace = true hex-literal.workspace = true thiserror.workspace = true tokio.workspace = true +serde.workspace = true +url.workspace = true [lints] workspace = true diff --git a/crates/signer/src/lib.rs b/crates/signer/src/lib.rs index e78f58cd..78e3d00a 100644 --- a/crates/signer/src/lib.rs +++ b/crates/signer/src/lib.rs @@ -4,3 +4,4 @@ )] pub mod signer; +pub mod web3_signer; diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index fa33b618..57e9bf26 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -1,3 +1,5 @@ +use crate::web3_signer::Web3Signer; +use alloy_primitives::{hex, Address}; use alloy_signer_aws::{AwsSigner, AwsSignerError}; use alloy_signer_local::PrivateKeySigner; use aws_config::{BehaviorVersion, Region}; @@ -5,6 +7,7 @@ use aws_sdk_kms; use eth_keystore::decrypt_key; use std::path::Path; use thiserror::Error; +use url::Url; /// Represents the input params to create a signer #[derive(Debug)] @@ -24,6 +27,10 @@ pub enum SignerError { InvalidPrivateKey, #[error("invalid keystore password")] InvalidPassword, + #[error("invalid address")] + InvalidAddress, + #[error("invalid url")] + InvalidUrl, } impl Config { @@ -60,6 +67,14 @@ impl Config { let client = aws_sdk_kms::Client::new(&config); Ok(AwsSigner::new(client, key_id, chain_id).await?) } + + /// Creates a signer from an endpoint and address + pub fn web3_signer(endpoint: String, address: String) -> Result { + let url: Url = endpoint.parse().map_err(|_| SignerError::InvalidUrl)?; + let address = + Address::from_slice(&hex::decode(address).map_err(|_| SignerError::InvalidAddress)?); + Ok(Web3Signer::new(address, url)) + } } #[cfg(test)] diff --git a/crates/signer/src/web3_signer.rs b/crates/signer/src/web3_signer.rs new file mode 100644 index 00000000..c1f4a584 --- /dev/null +++ b/crates/signer/src/web3_signer.rs @@ -0,0 +1,66 @@ +use alloy_consensus::SignableTransaction; +use alloy_primitives::{Address, Bytes, TxKind, U256}; +use alloy_rpc_client::{ClientBuilder, ReqwestClient, RpcCall}; +use alloy_signer::Signature; +use serde::{Deserialize, Serialize}; +use url::Url; + +/// A signer that sends an rpc request to sign a transaction remotely +#[derive(Debug)] +pub struct Web3Signer { + /// Client used to send an RPC request + pub client: ReqwestClient, + /// Address of the account that intends to sign a transaction. + /// It must match the `from` field in the transaction. + pub address: Address, +} + +#[derive(Serialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +struct SignTransactionParams { + from: String, + to: TxKind, + gas: String, + gas_price: String, + nonce: String, + data: String, +} + +#[derive(Deserialize, Clone, Debug)] +struct SignTransactionResponse { + r: U256, + s: U256, + parity: bool, +} + +impl Web3Signer { + /// TODO: add docs + pub fn new(address: Address, url: Url) -> Self { + Web3Signer { + client: ClientBuilder::default().http(url), + address, + } + } + + /// TODO: implement alloy TxSigner trait + pub async fn sign_transaction( + &self, + tx: &mut dyn SignableTransaction, + ) -> alloy_signer::Result { + let params = SignTransactionParams { + from: self.address.to_string(), + to: tx.to(), + gas: format!("0x{:x}", tx.gas_limit()), + gas_price: format!("0x{:x}", tx.gas_price().unwrap()), + nonce: format!("0x{:x}", tx.nonce()), + data: Bytes::copy_from_slice(tx.input()).to_string(), + }; + + let request: RpcCall<_, Vec, SignTransactionResponse> = + self.client.request("eth_signTransaction", vec![params]); + + let res = request.await.unwrap(); + + Signature::from_rs_and_parity(res.r, res.s, res.parity).map_err(alloy_signer::Error::from) + } +} From 191e38428e5a6b4eda974eb9bb9d20f40cb1c779 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Fri, 26 Jul 2024 17:47:29 -0300 Subject: [PATCH 22/82] add web3 signature test --- crates/signer/src/signer.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 57e9bf26..c967b586 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -174,4 +174,32 @@ mod test { signer.address() ); } + + #[tokio::test] + #[ignore = "missing test endpoint"] + async fn sign_transaction_with_web3_signer() { + // TODO: add a valid endpoint + let endpoint = "".to_string(); + let address = "b60e8dd61c5d32be8058bb8eb970870f07233155".to_string(); + let signer = Config::web3_signer(endpoint, address).unwrap(); + let mut tx = TxLegacy { + to: address!("d46e8dd67c5d32be8058bb8eb970870f07244567").into(), + value: U256::from(1_000_000_000), + gas_limit: 0x76c0, + nonce: 0, + gas_price: 21_000_000_000, + input: bytes!(), + chain_id: Some(1), + }; + + let sig = signer.sign_transaction(&mut tx).await.unwrap(); + + let mut encoded_tx = Vec::new(); + tx.encode_for_signing(&mut encoded_tx); + + assert_eq!( + sig.recover_address_from_msg(encoded_tx).unwrap(), + signer.address + ); + } } From 928deab6084aeff6bcfcbcd0f50612c1753eb744 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Fri, 26 Jul 2024 19:01:47 -0300 Subject: [PATCH 23/82] simple tx manager progress --- crates/chainio/txmanager/Cargo.toml | 1 + .../txmanager/src/simple_tx_manager.rs | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index 03f6525a..4e027dc9 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -11,3 +11,4 @@ license-file.workspace = true [dependencies] alloy-network.workspace = true alloy-primitives.workspace = true +alloy-contracts.workspace = true diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 78f731af..a684bfbe 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -1,3 +1,11 @@ +//use alloy::{ +// network::TransactionBuilder, +// node_bindings::Anvil, +// primitives::U256, +// providers::{Provider, ProviderBuilder}, +// rpc::types::TransactionRequest, +//}; + use alloy_network::{Ethereum, EthereumWallet}; use alloy_primitives::{address, fixed_bytes, Address, Bytes, FixedBytes, B256, I256, U256}; //use alloy_provider::Provider; @@ -40,4 +48,58 @@ impl SimpleTxManager { pub fn with_gas_limit_multiplier(&mut self, multiplier: f64) { self.gas_limit_multiplier = multiplier; } + + /* + // Spin up a local Anvil node. + // Ensure `anvil` is available in $PATH. + let anvil = Anvil::new().try_spawn()?; + + // Create a provider. + let rpc_url = anvil.endpoint().parse()?; + let provider = ProviderBuilder::new().on_http(rpc_url); + + // Create two users, Alice and Bob. + let alice = anvil.addresses()[0]; + let bob = anvil.addresses()[1]; + + // Build a transaction to send 100 wei from Alice to Bob. + // The `from` field is automatically filled to the first signer's address (Alice). + let tx = TransactionRequest::default() + .with_to(bob) + .with_nonce(0) + .with_chain_id(anvil.chain_id()) + .with_value(U256::from(100)) + .with_gas_limit(21_000) + .with_max_priority_fee_per_gas(1_000_000_000) + .with_max_fee_per_gas(20_000_000_000); + + // Send the transaction and wait for the broadcast. + let pending_tx = provider.send_transaction(tx).await?; + + println!("Pending transaction... {}", pending_tx.tx_hash()); + + // Wait for the transaction to be included and get the receipt. + let receipt = pending_tx.get_receipt().await?; + + println!( + "Transaction included in block {}", + receipt.block_number.expect("Failed to get block number") + ); + + assert_eq!(receipt.from, alice); + assert_eq!(receipt.to, Some(bob)); + + Ok(()) + */ + + pub fn send() { + let tx = TransactionRequest::default() + .with_to(bob) + .with_nonce(0) + .with_chain_id(anvil.chain_id()) + .with_value(U256::from(100)) + .with_gas_limit(21_000) + .with_max_priority_fee_per_gas(1_000_000_000) + .with_max_fee_per_gas(20_000_000_000); + } } From f583ebbffb2328c7ca60918b53407eddeb4c62c6 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Fri, 26 Jul 2024 19:18:08 -0300 Subject: [PATCH 24/82] add rlp decoding to rpc signer --- Cargo.lock | 1 + crates/signer/Cargo.toml | 4 +--- crates/signer/src/signer.rs | 37 ++++++++++++-------------------- crates/signer/src/web3_signer.rs | 19 +++++++++------- 4 files changed, 27 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5cfeb20c..e0da39ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1992,6 +1992,7 @@ dependencies = [ "alloy-consensus", "alloy-network", "alloy-primitives", + "alloy-rlp", "alloy-rpc-client 0.2.0", "alloy-signer", "alloy-signer-aws", diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index 7563edf2..b88a4a7c 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -13,6 +13,7 @@ alloy-signer.workspace = true alloy-signer-aws.workspace = true alloy-signer-local.workspace = true alloy-rpc-client.workspace = true +alloy-rlp.workspace = true aws-config.workspace = true aws-sdk-kms.workspace = true eth-keystore.workspace = true @@ -21,6 +22,3 @@ thiserror.workspace = true tokio.workspace = true serde.workspace = true url.workspace = true - -[lints] -workspace = true diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index c967b586..ece6b560 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -1,5 +1,5 @@ use crate::web3_signer::Web3Signer; -use alloy_primitives::{hex, Address}; +use alloy_primitives::Address; use alloy_signer_aws::{AwsSigner, AwsSignerError}; use alloy_signer_local::PrivateKeySigner; use aws_config::{BehaviorVersion, Region}; @@ -16,8 +16,6 @@ pub enum Config { PrivateKey(String), /// Keystore path and password Keystore(String, String), - /// Web3 endpoint and address - Web3(String, String), } /// Possible errors raised in signer creation @@ -48,9 +46,6 @@ impl Config { PrivateKeySigner::from_slice(&private_key) .map_err(|_| SignerError::InvalidPrivateKey) } - Config::Web3(_endpoint, _address) => { - todo!() // We are implementing this in a following PR - } } } /// Creates a signer from a key ID in AWS Key Management Service @@ -65,14 +60,11 @@ impl Config { .region(Some(region)) .build(); let client = aws_sdk_kms::Client::new(&config); - Ok(AwsSigner::new(client, key_id, chain_id).await?) + AwsSigner::new(client, key_id, chain_id).await } - /// Creates a signer from an endpoint and address - pub fn web3_signer(endpoint: String, address: String) -> Result { + pub fn web3_signer(endpoint: String, address: Address) -> Result { let url: Url = endpoint.parse().map_err(|_| SignerError::InvalidUrl)?; - let address = - Address::from_slice(&hex::decode(address).map_err(|_| SignerError::InvalidAddress)?); Ok(Web3Signer::new(address, url)) } } @@ -88,6 +80,7 @@ mod test { use alloy_signer::Signature; use alloy_signer_local::PrivateKeySigner; use std::str::FromStr; + use tokio; const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; const ADDRESS: [u8; 20] = hex!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); @@ -149,6 +142,7 @@ mod test { #[tokio::test] async fn sign_transaction_with_aws_signer() { + // TODO: use localstack let key_id = "1234abcd-12ab-34cd-56ef-1234567890ab".to_string(); let chain_id = Some(1); let region = Region::from_static("us-west-2a"); @@ -176,14 +170,13 @@ mod test { } #[tokio::test] - #[ignore = "missing test endpoint"] async fn sign_transaction_with_web3_signer() { - // TODO: add a valid endpoint - let endpoint = "".to_string(); - let address = "b60e8dd61c5d32be8058bb8eb970870f07233155".to_string(); + // TODO: replace hardcoded addresses with anvil + let endpoint = "http://127.0.0.1:8545 ".to_string(); + let address = address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); let signer = Config::web3_signer(endpoint, address).unwrap(); let mut tx = TxLegacy { - to: address!("d46e8dd67c5d32be8058bb8eb970870f07244567").into(), + to: address!("70997970C51812dc3A010C7d01b50e0d17dc79C8").into(), value: U256::from(1_000_000_000), gas_limit: 0x76c0, nonce: 0, @@ -192,14 +185,12 @@ mod test { chain_id: Some(1), }; - let sig = signer.sign_transaction(&mut tx).await.unwrap(); + let signature = signer.sign_transaction(&mut tx).await.unwrap(); - let mut encoded_tx = Vec::new(); - tx.encode_for_signing(&mut encoded_tx); + let private_key = hex!("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"); + let expected_signer = PrivateKeySigner::from_slice(&private_key).unwrap(); + let expected_signature = expected_signer.sign_transaction_sync(&mut tx).unwrap(); - assert_eq!( - sig.recover_address_from_msg(encoded_tx).unwrap(), - signer.address - ); + assert_eq!(signature, expected_signature); } } diff --git a/crates/signer/src/web3_signer.rs b/crates/signer/src/web3_signer.rs index c1f4a584..4c3d8caa 100644 --- a/crates/signer/src/web3_signer.rs +++ b/crates/signer/src/web3_signer.rs @@ -1,8 +1,9 @@ use alloy_consensus::SignableTransaction; use alloy_primitives::{Address, Bytes, TxKind, U256}; +use alloy_rlp::{Decodable, RlpDecodable}; use alloy_rpc_client::{ClientBuilder, ReqwestClient, RpcCall}; use alloy_signer::Signature; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use url::Url; /// A signer that sends an rpc request to sign a transaction remotely @@ -26,11 +27,12 @@ struct SignTransactionParams { data: String, } -#[derive(Deserialize, Clone, Debug)] +#[derive(Debug, RlpDecodable)] struct SignTransactionResponse { + // TODO: fill with tx fields r: U256, s: U256, - parity: bool, + parity: u8, } impl Web3Signer { @@ -42,7 +44,7 @@ impl Web3Signer { } } - /// TODO: implement alloy TxSigner trait + // TODO: implement alloy TxSigner trait pub async fn sign_transaction( &self, tx: &mut dyn SignableTransaction, @@ -56,11 +58,12 @@ impl Web3Signer { data: Bytes::copy_from_slice(tx.input()).to_string(), }; - let request: RpcCall<_, Vec, SignTransactionResponse> = + let request: RpcCall<_, Vec, Bytes> = self.client.request("eth_signTransaction", vec![params]); - let res = request.await.unwrap(); - - Signature::from_rs_and_parity(res.r, res.s, res.parity).map_err(alloy_signer::Error::from) + let mut rlp_encoded_signed_tx = request.await.unwrap(); + let signed_tx = SignTransactionResponse::decode(&mut rlp_encoded_signed_tx).unwrap(); // TODO: fix this + Signature::from_rs_and_parity(signed_tx.r, signed_tx.s, signed_tx.parity as u64) + .map_err(alloy_signer::Error::from) } } From 744b3591773882dbf373cd19d4f749359f5cc366 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Mon, 29 Jul 2024 17:39:25 -0300 Subject: [PATCH 25/82] add localstack setup to test the AWS signer --- Cargo.lock | 515 ++++++++++++++++++++++++++++++- Cargo.toml | 1 + crates/signer/Cargo.toml | 1 + crates/signer/src/signer.rs | 86 ++++-- crates/signer/src/web3_signer.rs | 4 +- 5 files changed, 579 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e0da39ca..f20afe29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -450,7 +450,7 @@ dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", "const-hex", - "heck", + "heck 0.5.0", "indexmap 2.2.6", "proc-macro-error", "proc-macro2", @@ -469,7 +469,7 @@ dependencies = [ "alloy-json-abi", "const-hex", "dunce", - "heck", + "heck 0.5.0", "proc-macro2", "quote", "serde_json", @@ -585,6 +585,21 @@ dependencies = [ "ws_stream_wasm", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anyhow" version = "1.0.86" @@ -1298,6 +1313,56 @@ dependencies = [ "zeroize", ] +[[package]] +name = "bollard" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aed08d3adb6ebe0eff737115056652670ae290f177759aac19c30456135f94c" +dependencies = [ + "base64 0.22.1", + "bollard-stubs", + "bytes", + "futures-core", + "futures-util", + "hex", + "home", + "http 1.1.0", + "http-body-util", + "hyper 1.3.1", + "hyper-named-pipe", + "hyper-rustls 0.26.0", + "hyper-util", + "hyperlocal-next", + "log", + "pin-project-lite", + "rustls 0.22.4", + "rustls-native-certs 0.7.1", + "rustls-pemfile 2.1.2", + "rustls-pki-types", + "serde", + "serde_derive", + "serde_json", + "serde_repr", + "serde_urlencoded", + "thiserror", + "tokio", + "tokio-util", + "tower-service", + "url", + "winapi", +] + +[[package]] +name = "bollard-stubs" +version = "1.44.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709d9aa1c37abb89d40f19f5d0ad6f0d88cb1581264e571c9350fc5bb89cf1c5" +dependencies = [ + "serde", + "serde_repr", + "serde_with", +] + [[package]] name = "bs58" version = "0.5.1" @@ -1435,7 +1500,11 @@ version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ + "android-tzdata", + "iana-time-zone", "num-traits", + "serde", + "windows-targets 0.52.5", ] [[package]] @@ -1627,6 +1696,41 @@ dependencies = [ "cipher", ] +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.67", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.67", +] + [[package]] name = "dashmap" version = "5.5.3" @@ -1663,6 +1767,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", + "serde", ] [[package]] @@ -1752,6 +1857,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "docker_credential" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31951f49556e34d90ed28342e1df7e1cb7a229c4cab0aecc627b5d91edd41d07" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + [[package]] name = "dunce" version = "1.0.4" @@ -2002,6 +2118,7 @@ dependencies = [ "eth-keystore", "hex-literal", "serde", + "testcontainers", "thiserror", "tokio", "url", @@ -2104,6 +2221,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "enum-as-inner" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.67", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -2844,6 +2973,12 @@ dependencies = [ "fxhash", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" @@ -2871,6 +3006,51 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hickory-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "hmac" version = "0.12.1" @@ -2889,6 +3069,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.12" @@ -3001,6 +3192,21 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-named-pipe" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" +dependencies = [ + "hex", + "hyper 1.3.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", + "winapi", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -3012,11 +3218,30 @@ dependencies = [ "hyper 0.14.29", "log", "rustls 0.21.12", - "rustls-native-certs", + "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", ] +[[package]] +name = "hyper-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.3.1", + "hyper-util", + "log", + "rustls 0.22.4", + "rustls-native-certs 0.7.1", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.25.0", + "tower-service", +] + [[package]] name = "hyper-rustls" version = "0.27.2" @@ -3028,6 +3253,7 @@ dependencies = [ "hyper 1.3.1", "hyper-util", "rustls 0.23.10", + "rustls-native-certs 0.7.1", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -3071,6 +3297,60 @@ dependencies = [ "tracing", ] +[[package]] +name = "hyperlocal-next" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf569d43fa9848e510358c07b80f4adf34084ddc28c6a4a651ee8474c070dcc" +dependencies = [ + "hex", + "http-body-util", + "hyper 1.3.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.5.0" @@ -3133,6 +3413,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -3143,6 +3424,7 @@ checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.5", + "serde", ] [[package]] @@ -3174,6 +3456,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg 0.50.0", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -3336,6 +3630,12 @@ dependencies = [ "libc", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -3367,6 +3667,15 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "mach2" version = "0.4.2" @@ -3376,6 +3685,12 @@ dependencies = [ "libc", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "md-5" version = "0.10.6" @@ -3723,6 +4038,31 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "parse-display" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914a1c2265c98e2446911282c6ac86d8524f495792c38c5bd884f80499c7538a" +dependencies = [ + "parse-display-derive", + "regex", + "regex-syntax", +] + +[[package]] +name = "parse-display-derive" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae7800a4c974efd12df917266338e79a7a74415173caf7e70aa0a0707345281" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "regex-syntax", + "structmeta", + "syn 2.0.67", +] + [[package]] name = "password-hash" version = "0.4.2" @@ -4283,6 +4623,7 @@ dependencies = [ "futures-core", "futures-util", "h2 0.4.5", + "hickory-resolver", "http 1.1.0", "http-body 1.0.0", "http-body-util", @@ -4300,6 +4641,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls 0.23.10", + "rustls-native-certs 0.7.1", "rustls-pemfile 2.1.2", "rustls-pki-types", "serde", @@ -4319,6 +4661,16 @@ dependencies = [ "winreg 0.52.0", ] +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -4481,6 +4833,20 @@ dependencies = [ "sct", ] +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring 0.17.8", + "rustls-pki-types", + "rustls-webpki 0.102.4", + "subtle", + "zeroize", +] + [[package]] name = "rustls" version = "0.23.10" @@ -4507,6 +4873,19 @@ dependencies = [ "security-framework", ] +[[package]] +name = "rustls-native-certs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.1.2", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -4764,6 +5143,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + [[package]] name = "serde_spanned" version = "0.6.6" @@ -4785,6 +5175,36 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.2.6", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.67", +] + [[package]] name = "sha1" version = "0.10.6" @@ -4959,6 +5379,35 @@ dependencies = [ "precomputed-hash", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "structmeta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329" +dependencies = [ + "proc-macro2", + "quote", + "structmeta-derive", + "syn 2.0.67", +] + +[[package]] +name = "structmeta-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] + [[package]] name = "strum" version = "0.26.2" @@ -4974,7 +5423,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", @@ -5112,6 +5561,35 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "testcontainers" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "725cbe485aafddfd8b2d01665937c95498d894c07fabd9c4e06a53c7da4ccc56" +dependencies = [ + "async-trait", + "bollard", + "bollard-stubs", + "bytes", + "dirs", + "docker_credential", + "either", + "futures", + "log", + "memchr", + "parse-display", + "pin-project-lite", + "reqwest 0.12.5", + "serde", + "serde_json", + "serde_with", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "url", +] + [[package]] name = "thiserror" version = "1.0.61" @@ -5256,6 +5734,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.0" @@ -5613,8 +6102,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", - "idna", + "idna 0.5.0", "percent-encoding", + "serde", ] [[package]] @@ -5794,6 +6284,12 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -5825,6 +6321,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 430847ed..728f4552 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -95,6 +95,7 @@ eth-keystore = "0.5.0" aws-config = "1.5.4" aws-sdk-kms = "1.37.0" url = "2.5.2" +testcontainers = "0.20.1" #misc parking_lot = "0.12" diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index b88a4a7c..61884b9f 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -22,3 +22,4 @@ thiserror.workspace = true tokio.workspace = true serde.workspace = true url.workspace = true +testcontainers.workspace = true diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index ece6b560..211985e8 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -2,8 +2,6 @@ use crate::web3_signer::Web3Signer; use alloy_primitives::Address; use alloy_signer_aws::{AwsSigner, AwsSignerError}; use alloy_signer_local::PrivateKeySigner; -use aws_config::{BehaviorVersion, Region}; -use aws_sdk_kms; use eth_keystore::decrypt_key; use std::path::Path; use thiserror::Error; @@ -52,14 +50,8 @@ impl Config { pub async fn aws_signer( key_id: String, chain_id: Option, - region: Region, + client: aws_sdk_kms::Client, ) -> Result { - let config = aws_config::load_defaults(BehaviorVersion::latest()) - .await - .to_builder() - .region(Some(region)) - .build(); - let client = aws_sdk_kms::Client::new(&config); AwsSigner::new(client, key_id, chain_id).await } @@ -72,14 +64,24 @@ impl Config { #[cfg(test)] mod test { use super::Config; - use super::*; use alloy_consensus::{SignableTransaction, TxLegacy}; use alloy_network::{TxSigner, TxSignerSync}; use alloy_primitives::hex_literal::hex; - use alloy_primitives::{address, bytes, Address, U256}; + use alloy_primitives::{address, bytes, keccak256, Address, U256}; use alloy_signer::Signature; use alloy_signer_local::PrivateKeySigner; + use aws_config::{BehaviorVersion, Region}; + use aws_sdk_kms::{ + self, + config::{Credentials, SharedCredentialsProvider}, + }; use std::str::FromStr; + use testcontainers::runners::AsyncRunner; + use testcontainers::ImageExt; + use testcontainers::{ + core::{IntoContainerPort, WaitFor}, + GenericImage, + }; use tokio; const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; @@ -91,7 +93,10 @@ mod test { const SIGNATURE_Y_PARITY: u64 = 37; const KEYSTORE_PATH: &str = "mockdata/dummy.key.json"; const KEYSTORE_PASSWORD: &str = "testpassword"; - + const LOCALSTACK_PORT: u16 = 4566; + const AWS_SOUTH_AMERICA_REGION: &str = "sa-east-1"; + const LOCALSTACK_IMAGE_NAME: &str = "localstack/localstack"; + const LOCALSTACK_IMAGE_TAG: &str = "latest"; #[test] fn sign_transaction_with_private_key() { let config = Config::PrivateKey(PRIVATE_KEY.into()); @@ -142,11 +147,46 @@ mod test { #[tokio::test] async fn sign_transaction_with_aws_signer() { - // TODO: use localstack - let key_id = "1234abcd-12ab-34cd-56ef-1234567890ab".to_string(); + // Start the container running Localstack + let _container = GenericImage::new(LOCALSTACK_IMAGE_NAME, LOCALSTACK_IMAGE_TAG) + .with_exposed_port(LOCALSTACK_PORT.tcp()) + .with_wait_for(WaitFor::message_on_stdout("Ready.")) + .with_mapped_port(LOCALSTACK_PORT, LOCALSTACK_PORT.tcp()) + .start() + .await + .unwrap(); + + // Set up the client configuration + let creds = Credentials::new("localstack", "localstack", None, None, "Static"); + let localstack_url: String = "http://localhost:".to_string() + &LOCALSTACK_PORT.to_string(); + let region = Region::from_static(&AWS_SOUTH_AMERICA_REGION); + let config = aws_config::load_defaults(BehaviorVersion::latest()) + .await + .to_builder() + .credentials_provider(SharedCredentialsProvider::new(creds)) + .endpoint_url(localstack_url) + .region(Some(region.clone())) + .build(); + + // Create an AWS KMS Client + let client = aws_sdk_kms::Client::new(&config); + + // Create a key + let key = client + .create_key() + .key_spec(aws_sdk_kms::types::KeySpec::EccSecgP256K1) + .key_usage(aws_sdk_kms::types::KeyUsageType::SignVerify) + .send() + .await + .unwrap(); + + // Create a signer for the given key + let key_id = key.key_metadata().unwrap().key_id(); let chain_id = Some(1); - let region = Region::from_static("us-west-2a"); - let signer = Config::aws_signer(key_id, chain_id, region).await.unwrap(); + let signer = Config::aws_signer(key_id.into(), chain_id, client.clone()) + .await + .unwrap(); + let mut tx = TxLegacy { to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(), value: U256::from(1_000_000_000), @@ -157,19 +197,21 @@ mod test { chain_id: Some(1), }; - // This request fails because key_id is not a valid key - let sig = signer.sign_transaction(&mut tx).await.unwrap(); + // Sign the transaction + let signature = signer.sign_transaction(&mut tx).await.unwrap(); + // Recover the address let mut encoded_tx = Vec::new(); tx.encode_for_signing(&mut encoded_tx); + let prehash = keccak256(encoded_tx); + let recovered_address = signature.recover_address_from_prehash(&prehash).unwrap(); - assert_eq!( - sig.recover_address_from_msg(encoded_tx).unwrap(), - signer.address() - ); + // Check that the recovered addresses are the same + assert_eq!(signer.address(), recovered_address); } #[tokio::test] + #[ignore = "work in progress"] async fn sign_transaction_with_web3_signer() { // TODO: replace hardcoded addresses with anvil let endpoint = "http://127.0.0.1:8545 ".to_string(); diff --git a/crates/signer/src/web3_signer.rs b/crates/signer/src/web3_signer.rs index 4c3d8caa..60f8d047 100644 --- a/crates/signer/src/web3_signer.rs +++ b/crates/signer/src/web3_signer.rs @@ -3,6 +3,7 @@ use alloy_primitives::{Address, Bytes, TxKind, U256}; use alloy_rlp::{Decodable, RlpDecodable}; use alloy_rpc_client::{ClientBuilder, ReqwestClient, RpcCall}; use alloy_signer::Signature; +use aws_sdk_kms::operation::sign; use serde::Serialize; use url::Url; @@ -62,7 +63,8 @@ impl Web3Signer { self.client.request("eth_signTransaction", vec![params]); let mut rlp_encoded_signed_tx = request.await.unwrap(); - let signed_tx = SignTransactionResponse::decode(&mut rlp_encoded_signed_tx).unwrap(); // TODO: fix this + let signed_tx = + SignTransactionResponse::decode(&mut rlp_encoded_signed_tx.as_ref()).unwrap(); // TODO: fix this Signature::from_rs_and_parity(signed_tx.r, signed_tx.s, signed_tx.parity as u64) .map_err(alloy_signer::Error::from) } From 778d76642275e377fa922cb9ddef8b2747ad7aff Mon Sep 17 00:00:00 2001 From: ricomateo Date: Mon, 29 Jul 2024 18:16:45 -0300 Subject: [PATCH 26/82] extract some of the code from the aws signer test to external functions --- crates/signer/src/signer.rs | 86 +++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 28 deletions(-) diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 211985e8..fd51c8a1 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -70,18 +70,21 @@ mod test { use alloy_primitives::{address, bytes, keccak256, Address, U256}; use alloy_signer::Signature; use alloy_signer_local::PrivateKeySigner; - use aws_config::{BehaviorVersion, Region}; + use aws_config::{BehaviorVersion, Region, SdkConfig}; + use aws_sdk_kms::config::StalledStreamProtectionConfig; + use aws_sdk_kms::operation::create_key::CreateKeyOutput; + use aws_sdk_kms::types::KeyMetadata; use aws_sdk_kms::{ self, config::{Credentials, SharedCredentialsProvider}, }; use std::str::FromStr; use testcontainers::runners::AsyncRunner; - use testcontainers::ImageExt; use testcontainers::{ core::{IntoContainerPort, WaitFor}, GenericImage, }; + use testcontainers::{ContainerAsync, ImageExt}; use tokio; const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; @@ -148,40 +151,25 @@ mod test { #[tokio::test] async fn sign_transaction_with_aws_signer() { // Start the container running Localstack - let _container = GenericImage::new(LOCALSTACK_IMAGE_NAME, LOCALSTACK_IMAGE_TAG) - .with_exposed_port(LOCALSTACK_PORT.tcp()) - .with_wait_for(WaitFor::message_on_stdout("Ready.")) - .with_mapped_port(LOCALSTACK_PORT, LOCALSTACK_PORT.tcp()) - .start() - .await - .unwrap(); + let _container = start_localstack_container().await; - // Set up the client configuration - let creds = Credentials::new("localstack", "localstack", None, None, "Static"); - let localstack_url: String = "http://localhost:".to_string() + &LOCALSTACK_PORT.to_string(); - let region = Region::from_static(&AWS_SOUTH_AMERICA_REGION); - let config = aws_config::load_defaults(BehaviorVersion::latest()) - .await - .to_builder() - .credentials_provider(SharedCredentialsProvider::new(creds)) - .endpoint_url(localstack_url) - .region(Some(region.clone())) - .build(); + let localstack_endpoint = "http://localhost:".to_string() + &LOCALSTACK_PORT.to_string(); + let config = get_aws_config( + "localstack".into(), + "localstack".into(), + Region::from_static(&AWS_SOUTH_AMERICA_REGION), + localstack_endpoint, + ) + .await; // Create an AWS KMS Client let client = aws_sdk_kms::Client::new(&config); // Create a key - let key = client - .create_key() - .key_spec(aws_sdk_kms::types::KeySpec::EccSecgP256K1) - .key_usage(aws_sdk_kms::types::KeyUsageType::SignVerify) - .send() - .await - .unwrap(); + let key_metadata = create_kms_key(&client).await; // Create a signer for the given key - let key_id = key.key_metadata().unwrap().key_id(); + let key_id = key_metadata.key_id(); let chain_id = Some(1); let signer = Config::aws_signer(key_id.into(), chain_id, client.clone()) .await @@ -235,4 +223,46 @@ mod test { assert_eq!(signature, expected_signature); } + + async fn start_localstack_container() -> ContainerAsync { + let container = GenericImage::new(LOCALSTACK_IMAGE_NAME, LOCALSTACK_IMAGE_TAG) + .with_exposed_port(LOCALSTACK_PORT.tcp()) + .with_wait_for(WaitFor::message_on_stdout("Ready.")) + .with_mapped_port(LOCALSTACK_PORT, LOCALSTACK_PORT.tcp()) + .start() + .await + .unwrap(); + container + } + + async fn create_kms_key(client: &aws_sdk_kms::Client) -> KeyMetadata { + client + .create_key() + .key_spec(aws_sdk_kms::types::KeySpec::EccSecgP256K1) + .key_usage(aws_sdk_kms::types::KeyUsageType::SignVerify) + .send() + .await + .unwrap() + .key_metadata() + .unwrap() + .clone() + } + + async fn get_aws_config( + access_key: String, + secret_access_key: String, + region: Region, + endpoint_url: String, + ) -> SdkConfig { + let creds = Credentials::new(access_key, secret_access_key, None, None, "Static"); + // let localstack_url: String = "http://localhost:".to_string() + &LOCALSTACK_PORT.to_string(); + let config = aws_config::load_defaults(BehaviorVersion::latest()) + .await + .to_builder() + .credentials_provider(SharedCredentialsProvider::new(creds)) + .endpoint_url(endpoint_url) + .region(Some(region.clone())) + .build(); + config + } } From 4ee612431c33fea0afbdbbc11eb9f4871e9fe705 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Mon, 29 Jul 2024 18:19:42 -0300 Subject: [PATCH 27/82] remove commented line --- crates/signer/src/signer.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index fd51c8a1..f0064cf8 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -255,7 +255,6 @@ mod test { endpoint_url: String, ) -> SdkConfig { let creds = Credentials::new(access_key, secret_access_key, None, None, "Static"); - // let localstack_url: String = "http://localhost:".to_string() + &LOCALSTACK_PORT.to_string(); let config = aws_config::load_defaults(BehaviorVersion::latest()) .await .to_builder() From 2c1c6093aa6b4fdcb00585237144b9ff46b463a3 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Mon, 29 Jul 2024 18:42:30 -0300 Subject: [PATCH 28/82] outline of tx manager copied from Go implementation --- Cargo.lock | 5 + crates/chainio/txmanager/Cargo.toml | 7 +- .../txmanager/src/simple_tx_manager.rs | 202 +++++++++++++++--- 3 files changed, 189 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34ac93ab..10686890 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1348,8 +1348,13 @@ dependencies = [ name = "eigen-chainio-txmanager" version = "0.0.1-alpha" dependencies = [ + "alloy-consensus", + "alloy-contract", + "alloy-eips", "alloy-network", "alloy-primitives", + "alloy-provider", + "alloy-signer", ] [[package]] diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index 4e027dc9..b55c1807 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -11,4 +11,9 @@ license-file.workspace = true [dependencies] alloy-network.workspace = true alloy-primitives.workspace = true -alloy-contracts.workspace = true +alloy-contract.workspace = true +alloy-provider.workspace = true +alloy-signer.workspace = true +alloy-consensus.workspace = true +alloy-eips.workspace = true +#logging.workspace = { path = "crates/chainio/utils/" } diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index a684bfbe..f1b82afe 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -6,8 +6,15 @@ // rpc::types::TransactionRequest, //}; +use alloy_consensus::{SignableTransaction, TxEip1559}; +use alloy_contract::SolCallBuilder; use alloy_network::{Ethereum, EthereumWallet}; use alloy_primitives::{address, fixed_bytes, Address, Bytes, FixedBytes, B256, I256, U256}; +use alloy_provider::{Provider, ProviderBuilder}; +use alloy_signer::Signer; +//use alloy_transactions::TransactionRequest; + +//use alloy_sol_types::sol; //use alloy_provider::Provider; //use alloy_rpc_types::Filter; @@ -17,15 +24,67 @@ use alloy_primitives::{address, fixed_bytes, Address, Bytes, FixedBytes, B256, I //use eth_keystore::decrypt_key; //use std::path::Path; // -// + pub struct SimpleTxManager { wallet: EthereumWallet, // client: eth::Client, - // log: logging::Logger, + //log: logging::Logger, sender: Address, gas_limit_multiplier: f64, } +/* +Go interface: + +// ======== +type TxManager interface { + // Send is used to send a transaction + // It takes an unsigned transaction and then signs it before sending + // It also takes care of nonce management and gas estimation + Send(ctx context.Context, tx *types.Transaction) (*types.Receipt, error) + + // GetNoSendTxOpts This generates a noSend TransactOpts so that we can use + // this to generate the transaction without actually sending it + GetNoSendTxOpts() (*bind.TransactOpts, error) +} +// ======= + +// Send is used to send a transaction to the Ethereum node. It takes an unsigned/signed transaction +// and then sends it to the Ethereum node. +// It also takes care of gas estimation and adds a buffer to the gas limit +// If you pass in a signed transaction it will ignore the signature +// and resign the transaction after adding the nonce and gas limit. +// To check out the whole flow on how this works, check out the README.md in this folder +func (m *SimpleTxManager) Send(ctx context.Context, tx *types.Transaction) (*types.Receipt, error) { + // Estimate gas and nonce + // can't print tx hash in logs because the tx changes below when we complete and sign it + // so the txHash is meaningless at this point + // ... +} + +func NoopSigner(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { + return tx, nil +} + +// GetNoSendTxOpts This generates a noSend TransactOpts so that we can use +// this to generate the transaction without actually sending it +func (m *SimpleTxManager) GetNoSendTxOpts() (*bind.TransactOpts, error) { +} + +func (m *SimpleTxManager) waitForReceipt(ctx context.Context, txID wallet.TxID) (*types.Receipt, error) { +} + +func (m *SimpleTxManager) queryReceipt(ctx context.Context, txID wallet.TxID) *types.Receipt { +} + +// estimateGasAndNonce we are explicitly implementing this because +// * We want to support legacy transactions (i.e. not dynamic fee) +// * We want to support gas management, i.e. add buffer to gas limit +func (m *SimpleTxManager) estimateGasAndNonce(ctx context.Context, tx *types.Transaction) (*types.Transaction, error) { +} + +*/ + impl SimpleTxManager { /* pub fn new( @@ -49,21 +108,53 @@ impl SimpleTxManager { self.gas_limit_multiplier = multiplier; } - /* - // Spin up a local Anvil node. - // Ensure `anvil` is available in $PATH. - let anvil = Anvil::new().try_spawn()?; + pub fn send() { + /* + // Spin up a local Anvil node. + // Ensure `anvil` is available in $PATH. + let anvil = Anvil::new().try_spawn()?; + + // Create a provider. + let rpc_url = anvil.endpoint().parse()?; + let provider = ProviderBuilder::new().on_http(rpc_url); + + // Create two users, Alice and Bob. + let alice = anvil.addresses()[0]; + let bob = anvil.addresses()[1]; + */ + + // ##################### + + /* + // Set up the provider + let provider = Provider::::try_from("https://mainnet.infura.io/v3/YOUR-PROJECT-ID")?; + + // Set up the signer (you'll need to replace this with your actual private key) + let signer = Signer::from_private_key("YOUR_PRIVATE_KEY_HERE".parse()?); - // Create a provider. - let rpc_url = anvil.endpoint().parse()?; - let provider = ProviderBuilder::new().on_http(rpc_url); + // Create the transaction request + let tx = TransactionRequest::new() + .to(Address::from_str( + "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", + )?) + .value(U256::from(1_000_000_000_000_000_000u128)) // 1 ETH in wei + .gas_limit(21000) + .gas_price(provider.get_gas_price().await?) + .nonce( + provider + .get_transaction_count(signer.address(), None) + .await?, + ); - // Create two users, Alice and Bob. - let alice = anvil.addresses()[0]; - let bob = anvil.addresses()[1]; + // Sign and send the transaction + let signed_tx = signer.sign_transaction(&tx).await?; + let pending_tx = provider.send_raw_transaction(signed_tx.rlp()).await?; - // Build a transaction to send 100 wei from Alice to Bob. - // The `from` field is automatically filled to the first signer's address (Alice). + // Wait for the transaction to be mined + let receipt = pending_tx.await?; + println!("Transaction mined in block: {:?}", receipt.block_number); + + // ##################### let tx = TransactionRequest::default() .with_to(bob) .with_nonce(0) @@ -72,7 +163,9 @@ impl SimpleTxManager { .with_gas_limit(21_000) .with_max_priority_fee_per_gas(1_000_000_000) .with_max_fee_per_gas(20_000_000_000); + */ + /* // Send the transaction and wait for the broadcast. let pending_tx = provider.send_transaction(tx).await?; @@ -90,16 +183,77 @@ impl SimpleTxManager { assert_eq!(receipt.to, Some(bob)); Ok(()) - */ + */ + } +} - pub fn send() { - let tx = TransactionRequest::default() - .with_to(bob) - .with_nonce(0) - .with_chain_id(anvil.chain_id()) - .with_value(U256::from(100)) - .with_gas_limit(21_000) - .with_max_priority_fee_per_gas(1_000_000_000) - .with_max_fee_per_gas(20_000_000_000); +/* +async fn test() -> Result<(), Box> { +use alloy_contract::SolCallBuilder; +use alloy_network::Ethereum; +use alloy_primitives::{Address, U256}; +use alloy_provider::ProviderBuilder; +use alloy_sol_types::sol; + +sol! { + #[sol(rpc)] // <-- Important! Generates the necessary `MyContract` struct and function methods. + #[sol(bytecode = "0x1234")] // <-- Generates the `BYTECODE` static and the `deploy` method. + contract MyContract { + constructor(address) {} // The `deploy` method will also include any constructor arguments. + + #[derive(Debug)] + function doStuff(uint a, bool b) public payable returns(address c, bytes32 d); + } +} + +// Build a provider. +let provider = ProviderBuilder::new().with_recommended_fillers().on_builtin("http://localhost:8545").await?; + +// If `#[sol(bytecode = "0x...")]` is provided, the contract can be deployed with `MyContract::deploy`, +// and a new instance will be created. +let constructor_arg = Address::ZERO; +let contract = MyContract::deploy(&provider, constructor_arg).await?; + +// Otherwise, or if already deployed, a new contract instance can be created with `MyContract::new`. +let address = Address::ZERO; +let contract = MyContract::new(address, &provider); + +// Build a call to the `doStuff` function and configure it. +let a = U256::from(123); +let b = true; +let call_builder = contract.doStuff(a, b).value(U256::from(50e18 as u64)); + +// Send the call. Note that this is not broadcasted as a transaction. +let call_return = call_builder.call().await?; +println!("{call_return:?}"); // doStuffReturn { c: 0x..., d: 0x... } + +// Use `send` to broadcast the call as a transaction. +let _pending_tx = call_builder.send().await?; +Ok(()) +} +*/ + +// TODO! +// continue with this: +// https://github.com/alloy-rs/examples/blob/main/examples/transactions/examples/encode_decode_eip1559.rs +#[cfg(test)] +mod tests { + use alloy_consensus::{SignableTransaction, TxEip1559}; + use alloy_eips::eip2930::AccessList; + use alloy_primitives::{address, hex, TxKind, U256}; + + #[test] + fn test_tx() { + let tx = TxEip1559 { + chain_id: 1, + nonce: 0x42, + gas_limit: 44386, + to: TxKind::Call( address!("6069a6c32cf691f5982febae4faf8a6f3ab2f0f6")), + value: U256::from(0_u64), + input: hex!("a22cb4650000000000000000000000005eee75727d804a2b13038928d36f8b188945a57a0000000000000000000000000000000000000000000000000000000000000000").into(), + max_fee_per_gas: 0x4a817c800, + max_priority_fee_per_gas: 0x3b9aca00, + access_list: AccessList::default(), + }; } } From eb51c3b3c3e5c6f39b3e2ff85d468c5ba87e3118 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Mon, 29 Jul 2024 19:06:05 -0300 Subject: [PATCH 29/82] add rpc test with anvil --- Cargo.lock | 29 ++++++++++++++++++++++++++++- crates/signer/Cargo.toml | 2 +- crates/signer/src/signer.rs | 21 +++++++++++---------- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f20afe29..998c40f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -140,6 +140,17 @@ dependencies = [ "sha2", ] +[[package]] +name = "alloy-genesis" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca15afde1b6d15e3fc1c97421262b1bbb37aee45752e3c8b6d6f13f776554ff" +dependencies = [ + "alloy-primitives", + "alloy-serde", + "serde", +] + [[package]] name = "alloy-json-abi" version = "0.7.7" @@ -198,6 +209,22 @@ dependencies = [ "thiserror", ] +[[package]] +name = "alloy-node-bindings" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494b2fb0276a78ec13791446a417c2517eee5c8e8a8c520ae0681975b8056e5c" +dependencies = [ + "alloy-genesis", + "alloy-primitives", + "k256", + "serde_json", + "tempfile", + "thiserror", + "tracing", + "url", +] + [[package]] name = "alloy-primitives" version = "0.7.7" @@ -2107,8 +2134,8 @@ version = "0.0.1-alpha" dependencies = [ "alloy-consensus", "alloy-network", + "alloy-node-bindings", "alloy-primitives", - "alloy-rlp", "alloy-rpc-client 0.2.0", "alloy-signer", "alloy-signer-aws", diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index 61884b9f..117653cd 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -13,7 +13,6 @@ alloy-signer.workspace = true alloy-signer-aws.workspace = true alloy-signer-local.workspace = true alloy-rpc-client.workspace = true -alloy-rlp.workspace = true aws-config.workspace = true aws-sdk-kms.workspace = true eth-keystore.workspace = true @@ -23,3 +22,4 @@ tokio.workspace = true serde.workspace = true url.workspace = true testcontainers.workspace = true +alloy-node-bindings.workspace = true diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index f0064cf8..09596b3c 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -66,6 +66,7 @@ mod test { use super::Config; use alloy_consensus::{SignableTransaction, TxLegacy}; use alloy_network::{TxSigner, TxSignerSync}; + use alloy_node_bindings::Anvil; use alloy_primitives::hex_literal::hex; use alloy_primitives::{address, bytes, keccak256, Address, U256}; use alloy_signer::Signature; @@ -199,26 +200,26 @@ mod test { } #[tokio::test] - #[ignore = "work in progress"] - async fn sign_transaction_with_web3_signer() { - // TODO: replace hardcoded addresses with anvil - let endpoint = "http://127.0.0.1:8545 ".to_string(); - let address = address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); + async fn sign_legacy_transaction_with_web3_signer() { + let anvil = Anvil::default().spawn(); + + let endpoint = anvil.endpoint(); + let address = anvil.addresses()[0]; let signer = Config::web3_signer(endpoint, address).unwrap(); let mut tx = TxLegacy { - to: address!("70997970C51812dc3A010C7d01b50e0d17dc79C8").into(), + to: anvil.addresses()[1].into(), value: U256::from(1_000_000_000), gas_limit: 0x76c0, - nonce: 0, gas_price: 21_000_000_000, + nonce: 0, input: bytes!(), - chain_id: Some(1), + chain_id: Some(anvil.chain_id()), }; let signature = signer.sign_transaction(&mut tx).await.unwrap(); - let private_key = hex!("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"); - let expected_signer = PrivateKeySigner::from_slice(&private_key).unwrap(); + let private_key = anvil.keys()[0].clone(); + let expected_signer = PrivateKeySigner::from_field_bytes(&private_key.to_bytes()).unwrap(); let expected_signature = expected_signer.sign_transaction_sync(&mut tx).unwrap(); assert_eq!(signature, expected_signature); From b377cb461e6e5362bbe73da29074152fffab5b6a Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Mon, 29 Jul 2024 19:06:23 -0300 Subject: [PATCH 30/82] fix rpc response decoding --- crates/signer/src/web3_signer.rs | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/crates/signer/src/web3_signer.rs b/crates/signer/src/web3_signer.rs index 60f8d047..b5546930 100644 --- a/crates/signer/src/web3_signer.rs +++ b/crates/signer/src/web3_signer.rs @@ -1,9 +1,7 @@ -use alloy_consensus::SignableTransaction; +use alloy_consensus::{SignableTransaction, TxLegacy}; use alloy_primitives::{Address, Bytes, TxKind, U256}; -use alloy_rlp::{Decodable, RlpDecodable}; use alloy_rpc_client::{ClientBuilder, ReqwestClient, RpcCall}; use alloy_signer::Signature; -use aws_sdk_kms::operation::sign; use serde::Serialize; use url::Url; @@ -22,20 +20,14 @@ pub struct Web3Signer { struct SignTransactionParams { from: String, to: TxKind, + value: U256, gas: String, - gas_price: String, + #[serde(skip_serializing_if = "Option::is_none")] + gas_price: Option, nonce: String, data: String, } -#[derive(Debug, RlpDecodable)] -struct SignTransactionResponse { - // TODO: fill with tx fields - r: U256, - s: U256, - parity: u8, -} - impl Web3Signer { /// TODO: add docs pub fn new(address: Address, url: Url) -> Self { @@ -53,19 +45,20 @@ impl Web3Signer { let params = SignTransactionParams { from: self.address.to_string(), to: tx.to(), + value: tx.value(), gas: format!("0x{:x}", tx.gas_limit()), - gas_price: format!("0x{:x}", tx.gas_price().unwrap()), + gas_price: tx.gas_price().map(|price| format!("0x{:x}", price)), nonce: format!("0x{:x}", tx.nonce()), data: Bytes::copy_from_slice(tx.input()).to_string(), }; let request: RpcCall<_, Vec, Bytes> = self.client.request("eth_signTransaction", vec![params]); + let rlp_encoded_signed_tx = request.await.map_err(alloy_signer::Error::other)?; + + let signed_tx = TxLegacy::decode_signed_fields(&mut rlp_encoded_signed_tx.as_ref()) + .map_err(alloy_signer::Error::other)?; - let mut rlp_encoded_signed_tx = request.await.unwrap(); - let signed_tx = - SignTransactionResponse::decode(&mut rlp_encoded_signed_tx.as_ref()).unwrap(); // TODO: fix this - Signature::from_rs_and_parity(signed_tx.r, signed_tx.s, signed_tx.parity as u64) - .map_err(alloy_signer::Error::from) + Ok(*signed_tx.signature()) } } From 7b411d67cb67b2d6118bd33608c8e133a888f100 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Mon, 29 Jul 2024 19:10:35 -0300 Subject: [PATCH 31/82] update comments --- crates/signer/src/signer.rs | 3 +-- crates/signer/src/web3_signer.rs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 09596b3c..4447b77a 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -55,6 +55,7 @@ impl Config { AwsSigner::new(client, key_id, chain_id).await } + /// Creates a signer that uses the Web3Signer JSON-RPC API pub fn web3_signer(endpoint: String, address: Address) -> Result { let url: Url = endpoint.parse().map_err(|_| SignerError::InvalidUrl)?; Ok(Web3Signer::new(address, url)) @@ -72,8 +73,6 @@ mod test { use alloy_signer::Signature; use alloy_signer_local::PrivateKeySigner; use aws_config::{BehaviorVersion, Region, SdkConfig}; - use aws_sdk_kms::config::StalledStreamProtectionConfig; - use aws_sdk_kms::operation::create_key::CreateKeyOutput; use aws_sdk_kms::types::KeyMetadata; use aws_sdk_kms::{ self, diff --git a/crates/signer/src/web3_signer.rs b/crates/signer/src/web3_signer.rs index b5546930..1abe8787 100644 --- a/crates/signer/src/web3_signer.rs +++ b/crates/signer/src/web3_signer.rs @@ -29,7 +29,6 @@ struct SignTransactionParams { } impl Web3Signer { - /// TODO: add docs pub fn new(address: Address, url: Url) -> Self { Web3Signer { client: ClientBuilder::default().http(url), From f2b909fe5b7f155c5e4ed4ed2727d3c204342ba9 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Mon, 29 Jul 2024 19:23:06 -0300 Subject: [PATCH 32/82] add TxSigner implementation for Web3Signer --- Cargo.lock | 5 +++-- Cargo.toml | 1 + crates/signer/Cargo.toml | 1 + crates/signer/src/web3_signer.rs | 14 +++++++++++--- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 998c40f8..e2a1e192 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -849,9 +849,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", @@ -2140,6 +2140,7 @@ dependencies = [ "alloy-signer", "alloy-signer-aws", "alloy-signer-local", + "async-trait", "aws-config", "aws-sdk-kms", "eth-keystore", diff --git a/Cargo.toml b/Cargo.toml index 728f4552..fdce7d4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,7 @@ aws-config = "1.5.4" aws-sdk-kms = "1.37.0" url = "2.5.2" testcontainers = "0.20.1" +async-trait = "0.1.81" #misc parking_lot = "0.12" diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index 117653cd..95aa1be6 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -23,3 +23,4 @@ serde.workspace = true url.workspace = true testcontainers.workspace = true alloy-node-bindings.workspace = true +async-trait.workspace = true \ No newline at end of file diff --git a/crates/signer/src/web3_signer.rs b/crates/signer/src/web3_signer.rs index 1abe8787..0119b829 100644 --- a/crates/signer/src/web3_signer.rs +++ b/crates/signer/src/web3_signer.rs @@ -1,7 +1,9 @@ use alloy_consensus::{SignableTransaction, TxLegacy}; +use alloy_network::TxSigner; use alloy_primitives::{Address, Bytes, TxKind, U256}; use alloy_rpc_client::{ClientBuilder, ReqwestClient, RpcCall}; use alloy_signer::Signature; +use async_trait::async_trait; use serde::Serialize; use url::Url; @@ -35,12 +37,18 @@ impl Web3Signer { address, } } +} + +#[async_trait] +impl TxSigner for Web3Signer { + fn address(&self) -> Address { + self.address + } - // TODO: implement alloy TxSigner trait - pub async fn sign_transaction( + async fn sign_transaction( &self, tx: &mut dyn SignableTransaction, - ) -> alloy_signer::Result { + ) -> alloy_signer::Result { let params = SignTransactionParams { from: self.address.to_string(), to: tx.to(), From 74dbf3c1fbe9f1978f078be6ca7045fa3cdc2e5a Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Tue, 30 Jul 2024 12:22:26 -0300 Subject: [PATCH 33/82] fix EOF --- crates/signer/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index 95aa1be6..883623de 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -23,4 +23,4 @@ serde.workspace = true url.workspace = true testcontainers.workspace = true alloy-node-bindings.workspace = true -async-trait.workspace = true \ No newline at end of file +async-trait.workspace = true From 0272657797f2715162dc2d6798fe6e7bd500d3d0 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Tue, 30 Jul 2024 12:29:34 -0300 Subject: [PATCH 34/82] minor changes --- crates/signer/src/lib.rs | 4 ++-- crates/signer/src/signer.rs | 1 + crates/signer/src/web3_signer.rs | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/signer/src/lib.rs b/crates/signer/src/lib.rs index 78e3d00a..ac1cd13c 100644 --- a/crates/signer/src/lib.rs +++ b/crates/signer/src/lib.rs @@ -1,6 +1,6 @@ #![doc( - html_logo_url = "https://github.com/supernovahs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", - issue_tracker_base_url = "https://github.com/supernovahs/eigen-rs/issues/" + html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", + issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" )] pub mod signer; diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 4447b77a..1a894963 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -100,6 +100,7 @@ mod test { const AWS_SOUTH_AMERICA_REGION: &str = "sa-east-1"; const LOCALSTACK_IMAGE_NAME: &str = "localstack/localstack"; const LOCALSTACK_IMAGE_TAG: &str = "latest"; + #[test] fn sign_transaction_with_private_key() { let config = Config::PrivateKey(PRIVATE_KEY.into()); diff --git a/crates/signer/src/web3_signer.rs b/crates/signer/src/web3_signer.rs index 0119b829..ee82ff08 100644 --- a/crates/signer/src/web3_signer.rs +++ b/crates/signer/src/web3_signer.rs @@ -7,7 +7,9 @@ use async_trait::async_trait; use serde::Serialize; use url::Url; -/// A signer that sends an rpc request to sign a transaction remotely +/// A signer that sends an RPC request to sign a transaction remotely +/// Implements `eth_signTransaction` method of Consensys Web3 Signer +/// Reference: https://docs.web3signer.consensys.io/reference/api/json-rpc#eth_signtransaction #[derive(Debug)] pub struct Web3Signer { /// Client used to send an RPC request From ba0c1d34ad2e69017245c5913f570c2124ff3f44 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Tue, 30 Jul 2024 15:45:34 -0300 Subject: [PATCH 35/82] tx in parameter --- crates/chainio/txmanager/src/simple_tx_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index f1b82afe..b40098cd 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -108,7 +108,7 @@ impl SimpleTxManager { self.gas_limit_multiplier = multiplier; } - pub fn send() { + pub fn send(tx: &TxEip1559) { /* // Spin up a local Anvil node. // Ensure `anvil` is available in $PATH. From 0487d41ba7b6a283fc5f51335ad29c0b5cac42f5 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Tue, 30 Jul 2024 16:02:03 -0300 Subject: [PATCH 36/82] add requested changes --- Cargo.lock | 107 +++++++----------------------------- Cargo.toml | 4 +- crates/signer/Cargo.toml | 11 ++-- crates/signer/src/signer.rs | 16 +++--- 4 files changed, 35 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2a1e192..93c92722 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,7 +102,7 @@ dependencies = [ "alloy-provider", "alloy-rpc-types-eth", "alloy-sol-types", - "alloy-transport 0.1.2", + "alloy-transport", "futures", "futures-util", "thiserror", @@ -176,19 +176,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "alloy-json-rpc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e76a9feec2352c78545d1a37415699817bae8dc41654bd1bfe57d6cdd5433bd" -dependencies = [ - "alloy-primitives", - "serde", - "serde_json", - "thiserror", - "tracing", -] - [[package]] name = "alloy-network" version = "0.1.2" @@ -197,7 +184,7 @@ checksum = "dc122cbee2b8523854cc11d87bcd5773741602c553d2d2d106d82eeb9c16924a" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-json-rpc 0.1.2", + "alloy-json-rpc", "alloy-primitives", "alloy-rpc-types-eth", "alloy-serde", @@ -256,14 +243,14 @@ dependencies = [ "alloy-chains", "alloy-consensus", "alloy-eips", - "alloy-json-rpc 0.1.2", + "alloy-json-rpc", "alloy-network", "alloy-primitives", "alloy-pubsub", - "alloy-rpc-client 0.1.2", + "alloy-rpc-client", "alloy-rpc-types-eth", - "alloy-transport 0.1.2", - "alloy-transport-http 0.1.2", + "alloy-transport", + "alloy-transport-http", "alloy-transport-ws", "async-stream", "async-trait", @@ -287,9 +274,9 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702f330b7da123a71465ab9d39616292f8344a2811c28f2cc8d8438a69d79e35" dependencies = [ - "alloy-json-rpc 0.1.2", + "alloy-json-rpc", "alloy-primitives", - "alloy-transport 0.1.2", + "alloy-transport", "bimap", "futures", "serde", @@ -328,11 +315,11 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b40fcb53b2a9d0a78a4968b2eca8805a4b7011b9ee3fdfa2acaf137c5128f36b" dependencies = [ - "alloy-json-rpc 0.1.2", + "alloy-json-rpc", "alloy-primitives", "alloy-pubsub", - "alloy-transport 0.1.2", - "alloy-transport-http 0.1.2", + "alloy-transport", + "alloy-transport-http", "alloy-transport-ws", "futures", "pin-project", @@ -346,27 +333,6 @@ dependencies = [ "url", ] -[[package]] -name = "alloy-rpc-client" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a9e609524fa31c2c70eb24c0da60796809193ad4787a6dfe6d0db0d3ac112d" -dependencies = [ - "alloy-json-rpc 0.2.0", - "alloy-transport 0.2.0", - "alloy-transport-http 0.2.0", - "futures", - "pin-project", - "reqwest 0.12.5", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tower", - "tracing", - "url", -] - [[package]] name = "alloy-rpc-types" version = "0.1.2" @@ -533,7 +499,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245af9541f0a0dbd5258669c80dfe3af118164cacec978a520041fc130550deb" dependencies = [ - "alloy-json-rpc 0.1.2", + "alloy-json-rpc", "base64 0.22.1", "futures-util", "futures-utils-wasm", @@ -545,48 +511,14 @@ dependencies = [ "url", ] -[[package]] -name = "alloy-transport" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b44b0f6f4a2593b258fa7b6cae8968e6a4c404d9ef4f5bc74401f2d04fa23fa" -dependencies = [ - "alloy-json-rpc 0.2.0", - "base64 0.22.1", - "futures-util", - "futures-utils-wasm", - "serde", - "serde_json", - "thiserror", - "tokio", - "tower", - "tracing", - "url", -] - [[package]] name = "alloy-transport-http" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5619c017e1fdaa1db87f9182f4f0ed97c53d674957f4902fba655e972d359c6c" dependencies = [ - "alloy-json-rpc 0.1.2", - "alloy-transport 0.1.2", - "reqwest 0.12.5", - "serde_json", - "tower", - "tracing", - "url", -] - -[[package]] -name = "alloy-transport-http" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d8f1eefa8cb9e7550740ee330feba4fed303a77ad3085707546f9152a88c380" -dependencies = [ - "alloy-json-rpc 0.2.0", - "alloy-transport 0.2.0", + "alloy-json-rpc", + "alloy-transport", "reqwest 0.12.5", "serde_json", "tower", @@ -601,7 +533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c0aff8af5be5e58856c5cdd1e46db2c67c7ecd3a652d9100b4822c96c899947" dependencies = [ "alloy-pubsub", - "alloy-transport 0.1.2", + "alloy-transport", "futures", "http 1.1.0", "rustls 0.23.10", @@ -1937,7 +1869,7 @@ dependencies = [ "alloy-rpc-types", "alloy-signer", "alloy-signer-local", - "alloy-transport-http 0.1.2", + "alloy-transport-http", "ark-bn254", "ark-ff 0.4.2", "eigen-chainio-utils", @@ -2136,7 +2068,7 @@ dependencies = [ "alloy-network", "alloy-node-bindings", "alloy-primitives", - "alloy-rpc-client 0.2.0", + "alloy-rpc-client", "alloy-signer", "alloy-signer-aws", "alloy-signer-local", @@ -2144,7 +2076,6 @@ dependencies = [ "aws-config", "aws-sdk-kms", "eth-keystore", - "hex-literal", "serde", "testcontainers", "thiserror", @@ -2159,7 +2090,7 @@ dependencies = [ "alloy-network", "alloy-primitives", "alloy-provider", - "alloy-transport-http 0.1.2", + "alloy-transport-http", "eigen-utils", "once_cell", ] @@ -2184,7 +2115,7 @@ dependencies = [ "alloy-provider", "alloy-signer-local", "alloy-sol-types", - "alloy-transport-http 0.1.2", + "alloy-transport-http", "reqwest 0.12.5", ] diff --git a/Cargo.toml b/Cargo.toml index fdce7d4e..66c6b066 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -137,9 +137,9 @@ alloy-transport-ws = { version = "0.1", default-features = false } alloy-transport-ipc = { version = "0.1", default-features = false } alloy-pubsub = { version = "0.1", default-features = false } alloy-json-rpc = { version = "0.1", default-features = false } -alloy-rpc-client = "0.2" +alloy-rpc-client = "0.1" alloy-contract = { version = "0.1", default-features = false } -alloy-signer-aws = "0.1.0" +alloy-signer-aws = "0.1" # examples diff --git a/crates/signer/Cargo.toml b/crates/signer/Cargo.toml index 883623de..a73dc9a9 100644 --- a/crates/signer/Cargo.toml +++ b/crates/signer/Cargo.toml @@ -13,14 +13,15 @@ alloy-signer.workspace = true alloy-signer-aws.workspace = true alloy-signer-local.workspace = true alloy-rpc-client.workspace = true -aws-config.workspace = true aws-sdk-kms.workspace = true eth-keystore.workspace = true -hex-literal.workspace = true thiserror.workspace = true -tokio.workspace = true serde.workspace = true url.workspace = true -testcontainers.workspace = true -alloy-node-bindings.workspace = true async-trait.workspace = true + +[dev-dependencies] +alloy-node-bindings.workspace = true +testcontainers.workspace = true +aws-config.workspace = true +tokio.workspace = true diff --git a/crates/signer/src/signer.rs b/crates/signer/src/signer.rs index 1a894963..d9079f80 100644 --- a/crates/signer/src/signer.rs +++ b/crates/signer/src/signer.rs @@ -68,23 +68,21 @@ mod test { use alloy_consensus::{SignableTransaction, TxLegacy}; use alloy_network::{TxSigner, TxSignerSync}; use alloy_node_bindings::Anvil; - use alloy_primitives::hex_literal::hex; - use alloy_primitives::{address, bytes, keccak256, Address, U256}; + use alloy_primitives::{address, bytes, hex_literal::hex, keccak256, Address, U256}; use alloy_signer::Signature; use alloy_signer_local::PrivateKeySigner; use aws_config::{BehaviorVersion, Region, SdkConfig}; - use aws_sdk_kms::types::KeyMetadata; use aws_sdk_kms::{ self, config::{Credentials, SharedCredentialsProvider}, + types::KeyMetadata, }; use std::str::FromStr; - use testcontainers::runners::AsyncRunner; use testcontainers::{ core::{IntoContainerPort, WaitFor}, - GenericImage, + runners::AsyncRunner, + ContainerAsync, GenericImage, ImageExt, }; - use testcontainers::{ContainerAsync, ImageExt}; use tokio; const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; @@ -149,12 +147,13 @@ mod test { assert_eq!(signature, expected_signature); } + // This test will fail if docker is not running #[tokio::test] async fn sign_transaction_with_aws_signer() { // Start the container running Localstack let _container = start_localstack_container().await; - let localstack_endpoint = "http://localhost:".to_string() + &LOCALSTACK_PORT.to_string(); + let localstack_endpoint = format!("http://localhost:{}", LOCALSTACK_PORT); let config = get_aws_config( "localstack".into(), "localstack".into(), @@ -199,6 +198,7 @@ mod test { assert_eq!(signer.address(), recovered_address); } + // This test will fail if anvil is not installed (Foundry contains anvil) #[tokio::test] async fn sign_legacy_transaction_with_web3_signer() { let anvil = Anvil::default().spawn(); @@ -232,7 +232,7 @@ mod test { .with_mapped_port(LOCALSTACK_PORT, LOCALSTACK_PORT.tcp()) .start() .await - .unwrap(); + .expect("Error starting localstack container"); container } From 6d6dd1feec1c3be1f572c722a051f276a4eb4f06 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Tue, 30 Jul 2024 17:43:15 -0300 Subject: [PATCH 37/82] alloy-eips as a dev dependency --- crates/chainio/txmanager/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index b55c1807..0a039915 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -15,5 +15,7 @@ alloy-contract.workspace = true alloy-provider.workspace = true alloy-signer.workspace = true alloy-consensus.workspace = true -alloy-eips.workspace = true #logging.workspace = { path = "crates/chainio/utils/" } + +[dev-dependencies] +alloy-eips.workspace = true From 72bd732540f5e7d1829a6b4a265228bc1dcb8750 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Tue, 30 Jul 2024 17:54:42 -0300 Subject: [PATCH 38/82] skeleton for wait for receipt --- Cargo.lock | 1 + crates/chainio/txmanager/Cargo.toml | 1 + .../txmanager/src/simple_tx_manager.rs | 22 +++++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1b150fa..442e480d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1857,6 +1857,7 @@ dependencies = [ "alloy-network", "alloy-primitives", "alloy-provider", + "alloy-rpc-client", "alloy-signer", ] diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index 0a039915..90a275af 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -15,6 +15,7 @@ alloy-contract.workspace = true alloy-provider.workspace = true alloy-signer.workspace = true alloy-consensus.workspace = true +alloy-rpc-client.workspace = true #logging.workspace = { path = "crates/chainio/utils/" } [dev-dependencies] diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index b40098cd..4f68f9c5 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -9,11 +9,12 @@ use alloy_consensus::{SignableTransaction, TxEip1559}; use alloy_contract::SolCallBuilder; use alloy_network::{Ethereum, EthereumWallet}; -use alloy_primitives::{address, fixed_bytes, Address, Bytes, FixedBytes, B256, I256, U256}; +use alloy_primitives::{address, fixed_bytes, Address, Bytes, FixedBytes, B256, I256, U256, U64}; use alloy_provider::{Provider, ProviderBuilder}; +use alloy_rpc_client::PollerBuilder; use alloy_signer::Signer; +// use futures_util::StreamExt; //use alloy_transactions::TransactionRequest; - //use alloy_sol_types::sol; //use alloy_provider::Provider; //use alloy_rpc_types::Filter; @@ -185,6 +186,23 @@ impl SimpleTxManager { Ok(()) */ } + + /// Waits for the transaction receipt. + /// The waiting is done by polling the node for the transaction receipt, using `PollerBuilder` + /// in `alloy_rpc_client` + pub fn wait_for_receipt() { + // # async fn example(client: alloy_rpc_client::RpcClient) -> Result<(), Box> { + // + // let poller: PollerBuilder<_, (), U64> = client + // .prepare_static_poller("eth_blockNumber", ()) + // .with_poll_interval(std::time::Duration::from_secs(5)); + // let mut stream = poller.into_stream(); + // while let Some(block_number) = stream.next().await { + // println!("polled block number: {block_number}"); + // } + // # Ok(()) + // # } + } } /* From 1ca0f5978e48e803685557b49ec28def1ccfd8d3 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 31 Jul 2024 16:28:41 -0300 Subject: [PATCH 39/82] polish example to send transaction --- Cargo.lock | 3 + crates/chainio/txmanager/Cargo.toml | 3 + .../txmanager/src/simple_tx_manager.rs | 144 +++++++----------- 3 files changed, 58 insertions(+), 92 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 442e480d..8b53037e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1855,10 +1855,13 @@ dependencies = [ "alloy-contract", "alloy-eips", "alloy-network", + "alloy-node-bindings", "alloy-primitives", "alloy-provider", "alloy-rpc-client", "alloy-signer", + "eigen-signer", + "tokio", ] [[package]] diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index 90a275af..c7ffe1e0 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -20,3 +20,6 @@ alloy-rpc-client.workspace = true [dev-dependencies] alloy-eips.workspace = true +alloy-node-bindings.workspace = true +tokio.workspace = true +eigen-signer = { path = "../../signer" } diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 4f68f9c5..2991cdf8 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -1,30 +1,6 @@ -//use alloy::{ -// network::TransactionBuilder, -// node_bindings::Anvil, -// primitives::U256, -// providers::{Provider, ProviderBuilder}, -// rpc::types::TransactionRequest, -//}; - -use alloy_consensus::{SignableTransaction, TxEip1559}; -use alloy_contract::SolCallBuilder; -use alloy_network::{Ethereum, EthereumWallet}; -use alloy_primitives::{address, fixed_bytes, Address, Bytes, FixedBytes, B256, I256, U256, U64}; -use alloy_provider::{Provider, ProviderBuilder}; -use alloy_rpc_client::PollerBuilder; -use alloy_signer::Signer; -// use futures_util::StreamExt; -//use alloy_transactions::TransactionRequest; -//use alloy_sol_types::sol; -//use alloy_provider::Provider; -//use alloy_rpc_types::Filter; - -// TODO!!! - -//use alloy_signer_local::PrivateKeySigner; -//use eth_keystore::decrypt_key; -//use std::path::Path; -// +use alloy_consensus::TxEip1559; +use alloy_network::EthereumWallet; +use alloy_primitives::Address; pub struct SimpleTxManager { wallet: EthereumWallet, @@ -205,73 +181,57 @@ impl SimpleTxManager { } } -/* -async fn test() -> Result<(), Box> { -use alloy_contract::SolCallBuilder; -use alloy_network::Ethereum; -use alloy_primitives::{Address, U256}; -use alloy_provider::ProviderBuilder; -use alloy_sol_types::sol; - -sol! { - #[sol(rpc)] // <-- Important! Generates the necessary `MyContract` struct and function methods. - #[sol(bytecode = "0x1234")] // <-- Generates the `BYTECODE` static and the `deploy` method. - contract MyContract { - constructor(address) {} // The `deploy` method will also include any constructor arguments. - - #[derive(Debug)] - function doStuff(uint a, bool b) public payable returns(address c, bytes32 d); - } -} - -// Build a provider. -let provider = ProviderBuilder::new().with_recommended_fillers().on_builtin("http://localhost:8545").await?; - -// If `#[sol(bytecode = "0x...")]` is provided, the contract can be deployed with `MyContract::deploy`, -// and a new instance will be created. -let constructor_arg = Address::ZERO; -let contract = MyContract::deploy(&provider, constructor_arg).await?; - -// Otherwise, or if already deployed, a new contract instance can be created with `MyContract::new`. -let address = Address::ZERO; -let contract = MyContract::new(address, &provider); - -// Build a call to the `doStuff` function and configure it. -let a = U256::from(123); -let b = true; -let call_builder = contract.doStuff(a, b).value(U256::from(50e18 as u64)); - -// Send the call. Note that this is not broadcasted as a transaction. -let call_return = call_builder.call().await?; -println!("{call_return:?}"); // doStuffReturn { c: 0x..., d: 0x... } - -// Use `send` to broadcast the call as a transaction. -let _pending_tx = call_builder.send().await?; -Ok(()) -} -*/ - -// TODO! -// continue with this: -// https://github.com/alloy-rs/examples/blob/main/examples/transactions/examples/encode_decode_eip1559.rs #[cfg(test)] mod tests { - use alloy_consensus::{SignableTransaction, TxEip1559}; - use alloy_eips::eip2930::AccessList; - use alloy_primitives::{address, hex, TxKind, U256}; - - #[test] - fn test_tx() { - let tx = TxEip1559 { - chain_id: 1, - nonce: 0x42, - gas_limit: 44386, - to: TxKind::Call( address!("6069a6c32cf691f5982febae4faf8a6f3ab2f0f6")), - value: U256::from(0_u64), - input: hex!("a22cb4650000000000000000000000005eee75727d804a2b13038928d36f8b188945a57a0000000000000000000000000000000000000000000000000000000000000000").into(), - max_fee_per_gas: 0x4a817c800, - max_priority_fee_per_gas: 0x3b9aca00, - access_list: AccessList::default(), + use alloy_consensus::TxLegacy; + use alloy_network::TxSigner; + use alloy_node_bindings::Anvil; + use alloy_primitives::{bytes, TxKind::Call, U256}; + use alloy_provider::{Provider, ProviderBuilder}; + use eigen_signer::signer::Config; + use tokio; + + const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; + + #[tokio::test] + async fn test_send_signed_transaction() { + // Spin up a local Anvil node. + // Ensure `anvil` is available in $PATH. + let anvil = Anvil::new().try_spawn().unwrap(); + + // Create a provider. + let rpc_url = anvil.endpoint().parse().unwrap(); + let provider = ProviderBuilder::new().on_http(rpc_url); + + // Create two users, Alice and Bob. + let _alice = anvil.addresses()[0]; + let bob = anvil.addresses()[1]; + + let config = Config::PrivateKey(PRIVATE_KEY.into()); + let signer = Config::signer_from_config(config).unwrap(); + + let mut tx = TxLegacy { + to: Call(bob), + value: U256::from(1_000_000_000), + gas_limit: 2_000_000, + nonce: 0, + gas_price: 21_000_000_000, + input: bytes!(), + chain_id: Some(31337), }; + let _signed_tx = signer.sign_transaction(&mut tx).await.unwrap(); + + // send transaction and get receipt + let receipt = provider + .send_transaction(tx.into()) + .await + .unwrap() + .get_receipt() + .await + .unwrap(); + // do something with the receipt + let block_number = receipt.block_number.unwrap(); + println!("Transaction mined in block: {:?}", block_number); + assert!(block_number > 0); } } From 9bcb285fc79bce4a1a0123090a7fc56fe661cef8 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 31 Jul 2024 16:31:13 -0300 Subject: [PATCH 40/82] tx sender example improved --- Cargo.lock | 2 -- crates/chainio/txmanager/Cargo.toml | 4 +--- crates/chainio/txmanager/src/simple_tx_manager.rs | 11 ++++------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b53037e..0f3dce71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1858,8 +1858,6 @@ dependencies = [ "alloy-node-bindings", "alloy-primitives", "alloy-provider", - "alloy-rpc-client", - "alloy-signer", "eigen-signer", "tokio", ] diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index c7ffe1e0..dff497b2 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -12,14 +12,12 @@ license-file.workspace = true alloy-network.workspace = true alloy-primitives.workspace = true alloy-contract.workspace = true -alloy-provider.workspace = true -alloy-signer.workspace = true alloy-consensus.workspace = true -alloy-rpc-client.workspace = true #logging.workspace = { path = "crates/chainio/utils/" } [dev-dependencies] alloy-eips.workspace = true alloy-node-bindings.workspace = true +alloy-provider.workspace = true tokio.workspace = true eigen-signer = { path = "../../signer" } diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 2991cdf8..8fc3fbce 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -222,13 +222,10 @@ mod tests { let _signed_tx = signer.sign_transaction(&mut tx).await.unwrap(); // send transaction and get receipt - let receipt = provider - .send_transaction(tx.into()) - .await - .unwrap() - .get_receipt() - .await - .unwrap(); + let pending_tx = provider.send_transaction(tx.into()).await.unwrap(); + + // wait for the transaction to be mined + let receipt = pending_tx.get_receipt().await.unwrap(); // do something with the receipt let block_number = receipt.block_number.unwrap(); println!("Transaction mined in block: {:?}", block_number); From 0fdfa0fc1e3cd907f475e631102cd522d809a111 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 31 Jul 2024 17:31:47 -0300 Subject: [PATCH 41/82] wait_for_receipt function polished --- Cargo.lock | 4 +- crates/chainio/txmanager/Cargo.toml | 6 ++- .../txmanager/src/simple_tx_manager.rs | 39 +++++++++++-------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f3dce71..e0b98f15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1852,13 +1852,15 @@ name = "eigen-chainio-txmanager" version = "0.0.1-alpha" dependencies = [ "alloy-consensus", - "alloy-contract", "alloy-eips", "alloy-network", "alloy-node-bindings", "alloy-primitives", "alloy-provider", + "alloy-transport", + "alloy-transport-http", "eigen-signer", + "reqwest 0.12.5", "tokio", ] diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index dff497b2..0259182e 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -11,13 +11,15 @@ license-file.workspace = true [dependencies] alloy-network.workspace = true alloy-primitives.workspace = true -alloy-contract.workspace = true alloy-consensus.workspace = true +alloy-provider.workspace = true +alloy-transport.workspace = true +alloy-transport-http.workspace = true +reqwest.workspace = true #logging.workspace = { path = "crates/chainio/utils/" } [dev-dependencies] alloy-eips.workspace = true alloy-node-bindings.workspace = true -alloy-provider.workspace = true tokio.workspace = true eigen-signer = { path = "../../signer" } diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 8fc3fbce..d9aebfb3 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -1,6 +1,10 @@ use alloy_consensus::TxEip1559; +use alloy_network::Ethereum; use alloy_network::EthereumWallet; use alloy_primitives::Address; +use alloy_provider::PendingTransactionBuilder; + +pub type Transport = alloy_transport_http::Http; pub struct SimpleTxManager { wallet: EthereumWallet, @@ -164,25 +168,28 @@ impl SimpleTxManager { } /// Waits for the transaction receipt. - /// The waiting is done by polling the node for the transaction receipt, using `PollerBuilder` - /// in `alloy_rpc_client` - pub fn wait_for_receipt() { - // # async fn example(client: alloy_rpc_client::RpcClient) -> Result<(), Box> { - // - // let poller: PollerBuilder<_, (), U64> = client - // .prepare_static_poller("eth_blockNumber", ()) - // .with_poll_interval(std::time::Duration::from_secs(5)); - // let mut stream = poller.into_stream(); - // while let Some(block_number) = stream.next().await { - // println!("polled block number: {block_number}"); - // } - // # Ok(()) - // # } + /// + /// This is a wrapper around `PendingTransactionBuilder::get_receipt`. + /// + /// # Arguments + /// + /// - `pending_tx`: The pending transaction builder we want to wait for. + /// + /// # Returns + /// + /// - The block number in which the transaction was included. + /// - `None` if the transaction was not included in a block or an error ocurred. + pub async fn wait_for_receipt( + pending_tx: PendingTransactionBuilder<'_, Transport, Ethereum>, + ) -> Option { + let receipt = pending_tx.get_receipt().await.ok()?; + receipt.block_number } } #[cfg(test)] mod tests { + use super::SimpleTxManager; use alloy_consensus::TxLegacy; use alloy_network::TxSigner; use alloy_node_bindings::Anvil; @@ -225,9 +232,7 @@ mod tests { let pending_tx = provider.send_transaction(tx.into()).await.unwrap(); // wait for the transaction to be mined - let receipt = pending_tx.get_receipt().await.unwrap(); - // do something with the receipt - let block_number = receipt.block_number.unwrap(); + let block_number = SimpleTxManager::wait_for_receipt(pending_tx).await.unwrap(); println!("Transaction mined in block: {:?}", block_number); assert!(block_number > 0); } From 451cc81354f6e2ecfe0e4c90633357616626fa74 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 31 Jul 2024 17:36:55 -0300 Subject: [PATCH 42/82] wait_for_receipt simplified --- Cargo.lock | 1 - crates/chainio/txmanager/Cargo.toml | 1 - crates/chainio/txmanager/src/simple_tx_manager.rs | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e0b98f15..297d5941 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1857,7 +1857,6 @@ dependencies = [ "alloy-node-bindings", "alloy-primitives", "alloy-provider", - "alloy-transport", "alloy-transport-http", "eigen-signer", "reqwest 0.12.5", diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index 0259182e..f24f7432 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -13,7 +13,6 @@ alloy-network.workspace = true alloy-primitives.workspace = true alloy-consensus.workspace = true alloy-provider.workspace = true -alloy-transport.workspace = true alloy-transport-http.workspace = true reqwest.workspace = true #logging.workspace = { path = "crates/chainio/utils/" } diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index d9aebfb3..b514721d 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -182,8 +182,7 @@ impl SimpleTxManager { pub async fn wait_for_receipt( pending_tx: PendingTransactionBuilder<'_, Transport, Ethereum>, ) -> Option { - let receipt = pending_tx.get_receipt().await.ok()?; - receipt.block_number + pending_tx.get_receipt().await.ok()?.block_number } } From 212d3f4e5b5a92bb3503b9db1c2d60fa7bffdee3 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 31 Jul 2024 17:48:04 -0300 Subject: [PATCH 43/82] wait_for_receipt returning a TransactionReceipt element --- Cargo.lock | 1 + Cargo.toml | 1 - crates/chainio/txmanager/Cargo.toml | 1 + .../txmanager/src/simple_tx_manager.rs | 35 ++++++------------- 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 297d5941..8c5f7b1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1857,6 +1857,7 @@ dependencies = [ "alloy-node-bindings", "alloy-primitives", "alloy-provider", + "alloy-rpc-types-eth", "alloy-transport-http", "eigen-signer", "reqwest 0.12.5", diff --git a/Cargo.toml b/Cargo.toml index f5442b6f..1c4b8271 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -143,7 +143,6 @@ alloy-rpc-client = "0.1" alloy-contract = { version = "0.1", default-features = false } alloy-signer-aws = "0.1" - # examples avsregistry-read = { path = "examples/avsregistry-read" } avsregistry-write = { path = "examples/avsregistry-write" } diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index f24f7432..26bdc3ab 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -14,6 +14,7 @@ alloy-primitives.workspace = true alloy-consensus.workspace = true alloy-provider.workspace = true alloy-transport-http.workspace = true +alloy-rpc-types-eth.workspace = true reqwest.workspace = true #logging.workspace = { path = "crates/chainio/utils/" } diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index b514721d..c17d9914 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -1,9 +1,9 @@ use alloy_consensus::TxEip1559; -use alloy_network::Ethereum; -use alloy_network::EthereumWallet; +use alloy_consensus::TxLegacy; +use alloy_network::{Ethereum, EthereumWallet}; use alloy_primitives::Address; use alloy_provider::PendingTransactionBuilder; - +use alloy_rpc_types_eth::TransactionReceipt; pub type Transport = alloy_transport_http::Http; pub struct SimpleTxManager { @@ -52,9 +52,6 @@ func NoopSigner(addr common.Address, tx *types.Transaction) (*types.Transaction, func (m *SimpleTxManager) GetNoSendTxOpts() (*bind.TransactOpts, error) { } -func (m *SimpleTxManager) waitForReceipt(ctx context.Context, txID wallet.TxID) (*types.Receipt, error) { -} - func (m *SimpleTxManager) queryReceipt(ctx context.Context, txID wallet.TxID) *types.Receipt { } @@ -90,19 +87,6 @@ impl SimpleTxManager { } pub fn send(tx: &TxEip1559) { - /* - // Spin up a local Anvil node. - // Ensure `anvil` is available in $PATH. - let anvil = Anvil::new().try_spawn()?; - - // Create a provider. - let rpc_url = anvil.endpoint().parse()?; - let provider = ProviderBuilder::new().on_http(rpc_url); - - // Create two users, Alice and Bob. - let alice = anvil.addresses()[0]; - let bob = anvil.addresses()[1]; - */ // ##################### @@ -161,12 +145,13 @@ impl SimpleTxManager { ); assert_eq!(receipt.from, alice); - assert_eq!(receipt.to, Some(bob)); Ok(()) */ } + pub fn send_legacy_tx(tx: &TxLegacy) {} + /// Waits for the transaction receipt. /// /// This is a wrapper around `PendingTransactionBuilder::get_receipt`. @@ -181,8 +166,8 @@ impl SimpleTxManager { /// - `None` if the transaction was not included in a block or an error ocurred. pub async fn wait_for_receipt( pending_tx: PendingTransactionBuilder<'_, Transport, Ethereum>, - ) -> Option { - pending_tx.get_receipt().await.ok()?.block_number + ) -> Option { + pending_tx.get_receipt().await.ok() } } @@ -231,8 +216,10 @@ mod tests { let pending_tx = provider.send_transaction(tx.into()).await.unwrap(); // wait for the transaction to be mined - let block_number = SimpleTxManager::wait_for_receipt(pending_tx).await.unwrap(); - println!("Transaction mined in block: {:?}", block_number); + let receipt = SimpleTxManager::wait_for_receipt(pending_tx).await.unwrap(); + let block_number = receipt.block_number.unwrap(); + println!("Transaction mined in block: {}", block_number); assert!(block_number > 0); + assert_eq!(receipt.to, Some(bob)); } } From 19bbce266028f81e223817362b27fb036b97c475 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 31 Jul 2024 18:24:42 -0300 Subject: [PATCH 44/82] send_legacy_tx first iteration --- Cargo.lock | 1 + crates/chainio/txmanager/Cargo.toml | 3 +- .../txmanager/src/simple_tx_manager.rs | 56 +++++++++++++++++-- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c5f7b1b..1ce1917d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1861,6 +1861,7 @@ dependencies = [ "alloy-transport-http", "eigen-signer", "reqwest 0.12.5", + "thiserror", "tokio", ] diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index 26bdc3ab..d0b8fde8 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -16,10 +16,11 @@ alloy-provider.workspace = true alloy-transport-http.workspace = true alloy-rpc-types-eth.workspace = true reqwest.workspace = true +eigen-signer = { path = "../../signer" } +thiserror = "1.0" #logging.workspace = { path = "crates/chainio/utils/" } [dev-dependencies] alloy-eips.workspace = true alloy-node-bindings.workspace = true tokio.workspace = true -eigen-signer = { path = "../../signer" } diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index c17d9914..0f29d909 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -1,17 +1,28 @@ -use alloy_consensus::TxEip1559; -use alloy_consensus::TxLegacy; -use alloy_network::{Ethereum, EthereumWallet}; +use alloy_consensus::{TxEip1559, TxLegacy}; +use alloy_network::{Ethereum, EthereumWallet, TxSigner}; use alloy_primitives::Address; -use alloy_provider::PendingTransactionBuilder; +use alloy_provider::{PendingTransactionBuilder, Provider, RootProvider}; use alloy_rpc_types_eth::TransactionReceipt; +use eigen_signer::signer::Config; +use thiserror::Error; + pub type Transport = alloy_transport_http::Http; +/// Possible errors raised in signer creation +#[derive(Error, Debug)] +pub enum TxManagerError { + #[error("wait_for_receipt error")] + WaitForReceipt, +} + pub struct SimpleTxManager { wallet: EthereumWallet, // client: eth::Client, //log: logging::Logger, sender: Address, gas_limit_multiplier: f64, + private_key: String, + provider: RootProvider, } /* @@ -150,7 +161,42 @@ impl SimpleTxManager { */ } - pub fn send_legacy_tx(tx: &TxLegacy) {} + /// Send is used to send a transaction to the Ethereum node. It takes an unsigned/signed transaction + /// and then sends it to the Ethereum node. + /// If you pass in a signed transaction it will ignore the signature + /// and resign the transaction after adding the nonce and gas limit. + /// + /// # Arguments + /// + /// - `tx`: The transaction to be sent. + /// + /// # Returns + /// + /// - The transaction receipt. + pub async fn send_legacy_tx(&self, tx: &mut TxLegacy) -> Option { + // TODO: It also takes care of gas estimation and adds a buffer to the gas limit + // TODO: Estimating gas and nonce + //m.log.Debug("Estimating gas and nonce") + //tx, err := m.estimateGasAndNonce(ctx, tx) + + let config = Config::PrivateKey(self.private_key.clone()); + let signer = Config::signer_from_config(config).unwrap(); + + let _signed_tx = signer.sign_transaction(tx).await.unwrap(); + + // send transaction and get receipt + let pending_tx = self + .provider + .send_transaction(tx.clone().into()) + .await + .unwrap(); + // Return: send: failed to estimate gas and nonce + + // wait for the transaction to be mined + let receipt = SimpleTxManager::wait_for_receipt(pending_tx).await.unwrap(); + // return: Transaction receipt not found + Some(receipt) + } /// Waits for the transaction receipt. /// From 4018375d6bcd46b8937590ecde7cedbd44fe75ba Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 31 Jul 2024 18:33:05 -0300 Subject: [PATCH 45/82] code cleanup --- .../txmanager/src/simple_tx_manager.rs | 99 +++++++------------ 1 file changed, 38 insertions(+), 61 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 0f29d909..78eb904a 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -8,11 +8,15 @@ use thiserror::Error; pub type Transport = alloy_transport_http::Http; -/// Possible errors raised in signer creation +/// Possible errors raised in Tx Manager #[derive(Error, Debug)] pub enum TxManagerError { + #[error("signer error")] + SignerError, + #[error("send error")] + SendTxError, #[error("wait_for_receipt error")] - WaitForReceipt, + WaitForReceiptError, } pub struct SimpleTxManager { @@ -25,55 +29,6 @@ pub struct SimpleTxManager { provider: RootProvider, } -/* -Go interface: - -// ======== -type TxManager interface { - // Send is used to send a transaction - // It takes an unsigned transaction and then signs it before sending - // It also takes care of nonce management and gas estimation - Send(ctx context.Context, tx *types.Transaction) (*types.Receipt, error) - - // GetNoSendTxOpts This generates a noSend TransactOpts so that we can use - // this to generate the transaction without actually sending it - GetNoSendTxOpts() (*bind.TransactOpts, error) -} -// ======= - -// Send is used to send a transaction to the Ethereum node. It takes an unsigned/signed transaction -// and then sends it to the Ethereum node. -// It also takes care of gas estimation and adds a buffer to the gas limit -// If you pass in a signed transaction it will ignore the signature -// and resign the transaction after adding the nonce and gas limit. -// To check out the whole flow on how this works, check out the README.md in this folder -func (m *SimpleTxManager) Send(ctx context.Context, tx *types.Transaction) (*types.Receipt, error) { - // Estimate gas and nonce - // can't print tx hash in logs because the tx changes below when we complete and sign it - // so the txHash is meaningless at this point - // ... -} - -func NoopSigner(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { - return tx, nil -} - -// GetNoSendTxOpts This generates a noSend TransactOpts so that we can use -// this to generate the transaction without actually sending it -func (m *SimpleTxManager) GetNoSendTxOpts() (*bind.TransactOpts, error) { -} - -func (m *SimpleTxManager) queryReceipt(ctx context.Context, txID wallet.TxID) *types.Receipt { -} - -// estimateGasAndNonce we are explicitly implementing this because -// * We want to support legacy transactions (i.e. not dynamic fee) -// * We want to support gas management, i.e. add buffer to gas limit -func (m *SimpleTxManager) estimateGasAndNonce(ctx context.Context, tx *types.Transaction) (*types.Transaction, error) { -} - -*/ - impl SimpleTxManager { /* pub fn new( @@ -173,29 +128,32 @@ impl SimpleTxManager { /// # Returns /// /// - The transaction receipt. - pub async fn send_legacy_tx(&self, tx: &mut TxLegacy) -> Option { + pub async fn send_legacy_tx( + &self, + tx: &mut TxLegacy, + ) -> Result { // TODO: It also takes care of gas estimation and adds a buffer to the gas limit // TODO: Estimating gas and nonce //m.log.Debug("Estimating gas and nonce") //tx, err := m.estimateGasAndNonce(ctx, tx) let config = Config::PrivateKey(self.private_key.clone()); - let signer = Config::signer_from_config(config).unwrap(); + let signer = Config::signer_from_config(config).map_err(|_| TxManagerError::SignerError)?; - let _signed_tx = signer.sign_transaction(tx).await.unwrap(); + let _signed_tx = signer + .sign_transaction(tx) + .await + .map_err(|_| TxManagerError::SignerError)?; // send transaction and get receipt let pending_tx = self .provider .send_transaction(tx.clone().into()) .await - .unwrap(); - // Return: send: failed to estimate gas and nonce + .map_err(|_| TxManagerError::SendTxError)?; // wait for the transaction to be mined - let receipt = SimpleTxManager::wait_for_receipt(pending_tx).await.unwrap(); - // return: Transaction receipt not found - Some(receipt) + SimpleTxManager::wait_for_receipt(pending_tx).await } /// Waits for the transaction receipt. @@ -212,9 +170,28 @@ impl SimpleTxManager { /// - `None` if the transaction was not included in a block or an error ocurred. pub async fn wait_for_receipt( pending_tx: PendingTransactionBuilder<'_, Transport, Ethereum>, - ) -> Option { - pending_tx.get_receipt().await.ok() + ) -> Result { + pending_tx + .get_receipt() + .await + .map_err(|_| TxManagerError::WaitForReceiptError) } + + /* + // GetNoSendTxOpts This generates a noSend TransactOpts so that we can use + // this to generate the transaction without actually sending it + func (m *SimpleTxManager) GetNoSendTxOpts() (*bind.TransactOpts, error) { + } + + func (m *SimpleTxManager) queryReceipt(ctx context.Context, txID wallet.TxID) *types.Receipt { + } + + // estimateGasAndNonce we are explicitly implementing this because + // * We want to support legacy transactions (i.e. not dynamic fee) + // * We want to support gas management, i.e. add buffer to gas limit + func (m *SimpleTxManager) estimateGasAndNonce(ctx context.Context, tx *types.Transaction) (*types.Transaction, error) { + } + */ } #[cfg(test)] From a575475e085f75e1215103c266f85c37ddb4c289 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 31 Jul 2024 19:09:11 -0300 Subject: [PATCH 46/82] send_eip1559_tx --- Cargo.lock | 1 + crates/chainio/txmanager/Cargo.toml | 1 + .../txmanager/src/simple_tx_manager.rs | 106 +++++++----------- 3 files changed, 42 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ce1917d..848aebd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1858,6 +1858,7 @@ dependencies = [ "alloy-primitives", "alloy-provider", "alloy-rpc-types-eth", + "alloy-signer-local", "alloy-transport-http", "eigen-signer", "reqwest 0.12.5", diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index d0b8fde8..515bae69 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -15,6 +15,7 @@ alloy-consensus.workspace = true alloy-provider.workspace = true alloy-transport-http.workspace = true alloy-rpc-types-eth.workspace = true +alloy-signer-local.workspace = true reqwest.workspace = true eigen-signer = { path = "../../signer" } thiserror = "1.0" diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 78eb904a..d432abc2 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -3,6 +3,7 @@ use alloy_network::{Ethereum, EthereumWallet, TxSigner}; use alloy_primitives::Address; use alloy_provider::{PendingTransactionBuilder, Provider, RootProvider}; use alloy_rpc_types_eth::TransactionReceipt; +use alloy_signer_local::PrivateKeySigner; use eigen_signer::signer::Config; use thiserror::Error; @@ -52,68 +53,44 @@ impl SimpleTxManager { self.gas_limit_multiplier = multiplier; } - pub fn send(tx: &TxEip1559) { - - // ##################### - - /* - // Set up the provider - let provider = Provider::::try_from("https://mainnet.infura.io/v3/YOUR-PROJECT-ID")?; - - // Set up the signer (you'll need to replace this with your actual private key) - let signer = Signer::from_private_key("YOUR_PRIVATE_KEY_HERE".parse()?); - - // Create the transaction request - let tx = TransactionRequest::new() - .to(Address::from_str( - "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", - )?) - .value(U256::from(1_000_000_000_000_000_000u128)) // 1 ETH in wei - .gas_limit(21000) - .gas_price(provider.get_gas_price().await?) - .nonce( - provider - .get_transaction_count(signer.address(), None) - .await?, - ); - - // Sign and send the transaction - let signed_tx = signer.sign_transaction(&tx).await?; - let pending_tx = provider.send_raw_transaction(signed_tx.rlp()).await?; - - // Wait for the transaction to be mined - let receipt = pending_tx.await?; - println!("Transaction mined in block: {:?}", receipt.block_number); - - // ##################### - let tx = TransactionRequest::default() - .with_to(bob) - .with_nonce(0) - .with_chain_id(anvil.chain_id()) - .with_value(U256::from(100)) - .with_gas_limit(21_000) - .with_max_priority_fee_per_gas(1_000_000_000) - .with_max_fee_per_gas(20_000_000_000); - */ - - /* - // Send the transaction and wait for the broadcast. - let pending_tx = provider.send_transaction(tx).await?; - - println!("Pending transaction... {}", pending_tx.tx_hash()); - - // Wait for the transaction to be included and get the receipt. - let receipt = pending_tx.get_receipt().await?; - - println!( - "Transaction included in block {}", - receipt.block_number.expect("Failed to get block number") - ); - - assert_eq!(receipt.from, alice); - - Ok(()) - */ + fn create_local_signer(&self) -> Result { + let config = Config::PrivateKey(self.private_key.clone()); + Config::signer_from_config(config).map_err(|_| TxManagerError::SignerError) + } + + /// Sends a EIP1559 transaction. + /// + /// Send is used to send a transaction to the Ethereum node. It takes an unsigned/signed transaction + /// and then sends it to the Ethereum node. + /// If you pass in a signed transaction it will ignore the signature + /// and resign the transaction after adding the nonce and gas limit. + /// + /// # Arguments + /// + /// - `tx`: The transaction to be sent. + /// + /// # Returns + /// + /// - The transaction receipt. + pub async fn send_eip1559_tx( + &self, + tx: &mut TxEip1559, + ) -> Result { + let signer = self.create_local_signer()?; + let _signed_tx = signer + .sign_transaction(tx) + .await + .map_err(|_| TxManagerError::SignerError)?; + + // send transaction and get receipt + let pending_tx = self + .provider + .send_transaction(tx.clone().into()) + .await + .map_err(|_| TxManagerError::SendTxError)?; + + // wait for the transaction to be mined + SimpleTxManager::wait_for_receipt(pending_tx).await } /// Send is used to send a transaction to the Ethereum node. It takes an unsigned/signed transaction @@ -136,10 +113,7 @@ impl SimpleTxManager { // TODO: Estimating gas and nonce //m.log.Debug("Estimating gas and nonce") //tx, err := m.estimateGasAndNonce(ctx, tx) - - let config = Config::PrivateKey(self.private_key.clone()); - let signer = Config::signer_from_config(config).map_err(|_| TxManagerError::SignerError)?; - + let signer = self.create_local_signer()?; let _signed_tx = signer .sign_transaction(tx) .await From 211bc61f7d15861cdf89b4312f3b307aad933392 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 1 Aug 2024 15:54:04 -0300 Subject: [PATCH 47/82] method new in SimpleTxManager --- Cargo.lock | 1 + Cargo.toml | 1 + crates/chainio/txmanager/Cargo.toml | 3 +- .../txmanager/src/simple_tx_manager.rs | 57 +++++++++++++------ 4 files changed, 43 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 848aebd3..176d0c7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1861,6 +1861,7 @@ dependencies = [ "alloy-signer-local", "alloy-transport-http", "eigen-signer", + "k256", "reqwest 0.12.5", "thiserror", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 1c4b8271..b63414df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -142,6 +142,7 @@ alloy-json-rpc = { version = "0.1", default-features = false } alloy-rpc-client = "0.1" alloy-contract = { version = "0.1", default-features = false } alloy-signer-aws = "0.1" +k256 = "0.13" # examples avsregistry-read = { path = "examples/avsregistry-read" } diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index 515bae69..d83fe746 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -17,8 +17,9 @@ alloy-transport-http.workspace = true alloy-rpc-types-eth.workspace = true alloy-signer-local.workspace = true reqwest.workspace = true +thiserror.workspace = true eigen-signer = { path = "../../signer" } -thiserror = "1.0" +k256.workspace = true #logging.workspace = { path = "crates/chainio/utils/" } [dev-dependencies] diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index d432abc2..9a8cb687 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -1,10 +1,12 @@ use alloy_consensus::{TxEip1559, TxLegacy}; -use alloy_network::{Ethereum, EthereumWallet, TxSigner}; +use alloy_network::{Ethereum, TxSigner}; use alloy_primitives::Address; -use alloy_provider::{PendingTransactionBuilder, Provider, RootProvider}; +use alloy_provider::{PendingTransactionBuilder, Provider, ProviderBuilder, RootProvider}; use alloy_rpc_types_eth::TransactionReceipt; use alloy_signer_local::PrivateKeySigner; use eigen_signer::signer::Config; +use k256::ecdsa::SigningKey; +use reqwest::Url; use thiserror::Error; pub type Transport = alloy_transport_http::Http; @@ -18,36 +20,49 @@ pub enum TxManagerError { SendTxError, #[error("wait_for_receipt error")] WaitForReceiptError, + #[error("address error")] + AddressError, + #[error("invalid url error")] + InvalidUrlError, } pub struct SimpleTxManager { - wallet: EthereumWallet, - // client: eth::Client, //log: logging::Logger, - sender: Address, gas_limit_multiplier: f64, private_key: String, provider: RootProvider, } impl SimpleTxManager { - /* pub fn new( - wallet: wallet::Wallet, - client: eth::Client, - log: logging::Logger, - sender: common::Address, + //log: logging::Logger, gas_limit_multiplier: f64, - ) -> SimpleTxManager { - SimpleTxManager { - wallet, - client, - log, - sender, + private_key: &str, + rpc_url: &str, + ) -> Result { + let url = Url::parse(rpc_url).map_err(|_| TxManagerError::InvalidUrlError)?; + let provider = ProviderBuilder::new().on_http(url); + Ok(SimpleTxManager { gas_limit_multiplier, - } + private_key: private_key.to_string(), + provider, + }) + } + + /// Returns the address of the wallet, beloing to the given private key. + /// + /// # Returns + /// + /// - The address of the wallet. + /// + /// # Errors + /// + /// - If the private key is invalid. + pub fn get_address(&self) -> Result { + let private_key_signing_key = SigningKey::from_slice(self.private_key.as_bytes()) + .map_err(|_| TxManagerError::AddressError)?; + Ok(Address::from_private_key(&private_key_signing_key)) } - */ pub fn with_gas_limit_multiplier(&mut self, multiplier: f64) { self.gas_limit_multiplier = multiplier; @@ -72,6 +87,12 @@ impl SimpleTxManager { /// # Returns /// /// - The transaction receipt. + /// + /// # Errors + /// + /// - If the transaction could not be signed. + /// - If the transaction could not be sent. + /// - If the transaction could not be mined. pub async fn send_eip1559_tx( &self, tx: &mut TxEip1559, From 42fcbc9ea8660708aa50010ba2988a900297c795 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 1 Aug 2024 16:00:25 -0300 Subject: [PATCH 48/82] reordering crates in Cargo.toml --- crates/chainio/txmanager/Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index d83fe746..647fc4d6 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -9,17 +9,17 @@ repository.workspace = true license-file.workspace = true [dependencies] +eigen-signer = { path = "../../signer" } +alloy-consensus.workspace = true alloy-network.workspace = true alloy-primitives.workspace = true -alloy-consensus.workspace = true alloy-provider.workspace = true -alloy-transport-http.workspace = true alloy-rpc-types-eth.workspace = true alloy-signer-local.workspace = true +alloy-transport-http.workspace = true +k256.workspace = true reqwest.workspace = true thiserror.workspace = true -eigen-signer = { path = "../../signer" } -k256.workspace = true #logging.workspace = { path = "crates/chainio/utils/" } [dev-dependencies] From bd6b41bc726051114d3fc9ffa9f2533cb9b897d7 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 1 Aug 2024 16:12:34 -0300 Subject: [PATCH 49/82] test_send_signed_transaction simplified using implemented methods --- .../chainio/txmanager/src/simple_tx_manager.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 9a8cb687..bc3f5a06 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -193,11 +193,8 @@ impl SimpleTxManager { mod tests { use super::SimpleTxManager; use alloy_consensus::TxLegacy; - use alloy_network::TxSigner; use alloy_node_bindings::Anvil; use alloy_primitives::{bytes, TxKind::Call, U256}; - use alloy_provider::{Provider, ProviderBuilder}; - use eigen_signer::signer::Config; use tokio; const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; @@ -207,18 +204,15 @@ mod tests { // Spin up a local Anvil node. // Ensure `anvil` is available in $PATH. let anvil = Anvil::new().try_spawn().unwrap(); + let rpc_url: String = anvil.endpoint().parse().unwrap(); // Create a provider. - let rpc_url = anvil.endpoint().parse().unwrap(); - let provider = ProviderBuilder::new().on_http(rpc_url); + let simple_tx_manager = SimpleTxManager::new(1.0, PRIVATE_KEY, rpc_url.as_str()).unwrap(); // Create two users, Alice and Bob. let _alice = anvil.addresses()[0]; let bob = anvil.addresses()[1]; - let config = Config::PrivateKey(PRIVATE_KEY.into()); - let signer = Config::signer_from_config(config).unwrap(); - let mut tx = TxLegacy { to: Call(bob), value: U256::from(1_000_000_000), @@ -228,13 +222,9 @@ mod tests { input: bytes!(), chain_id: Some(31337), }; - let _signed_tx = signer.sign_transaction(&mut tx).await.unwrap(); - - // send transaction and get receipt - let pending_tx = provider.send_transaction(tx.into()).await.unwrap(); - // wait for the transaction to be mined - let receipt = SimpleTxManager::wait_for_receipt(pending_tx).await.unwrap(); + //// send transaction and wait for receipt + let receipt = simple_tx_manager.send_legacy_tx(&mut tx).await.unwrap(); let block_number = receipt.block_number.unwrap(); println!("Transaction mined in block: {}", block_number); assert!(block_number > 0); From 81af8ef2d7983255b4c5cc6fdaa699b0ab93c788 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 1 Aug 2024 16:55:07 -0300 Subject: [PATCH 50/82] Adding reference to logger --- Cargo.lock | 2 ++ Cargo.toml | 3 +- crates/chainio/txmanager/Cargo.toml | 5 +-- .../txmanager/src/simple_tx_manager.rs | 35 +++++++++++++++---- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 086b9da2..f13d71fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1860,8 +1860,10 @@ dependencies = [ "alloy-rpc-types-eth", "alloy-signer-local", "alloy-transport-http", + "eigen-logging", "eigen-signer", "k256", + "once_cell", "reqwest 0.12.5", "thiserror", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 0f293701..252a3833 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ members = [ "crates/types/", "crates/metrics/", "crates/types/", - "crates/signer/", "crates/logging/", "crates/signer/", "examples/info-operator-service/", @@ -78,6 +77,7 @@ eigen-crypto-bls = { path = "crates/crypto/bls/" } eigen-crypto-bn254 = { path = "crates/crypto/bn254/" } eigen-crypto-keystore = { path = "crates/crypto/keystore/" } eigen-utils = { path = "crates/utils/" } +eigen-signer = { path = "crates/signer/" } eigen-metrics-collectors-economic = { path = "crates/metrics/collectors/economic" } eigen-metrics-collectors-rpc-calls = { path = "crates/metrics/collectors/rpc_calls" } eigen-services-avsregistry = { path = "crates/services/avsregistry" } @@ -85,6 +85,7 @@ eigen-services-bls_aggregation = { path = "crates/services/bls_aggregation" } eigen-services-operatorsinfo = { path = "crates/services/operatorsinfo" } eigen-metrics-derive = { path = "crates/metrics/metrics-derive" } eigen-testing-utils = { path = "testing/testing-utils" } +eigen-logging = { path = "crates/logging" } info-operator-service = { path = "examples/info-operator-service" } tokio = { version = "1.37.0", features = ["test-util", "full", "sync"] } futures-util = "0.3.30" diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index 647fc4d6..a6595db9 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -9,7 +9,8 @@ repository.workspace = true license-file.workspace = true [dependencies] -eigen-signer = { path = "../../signer" } +eigen-signer.workspace = true +eigen-logging.workspace = true alloy-consensus.workspace = true alloy-network.workspace = true alloy-primitives.workspace = true @@ -20,9 +21,9 @@ alloy-transport-http.workspace = true k256.workspace = true reqwest.workspace = true thiserror.workspace = true -#logging.workspace = { path = "crates/chainio/utils/" } [dev-dependencies] alloy-eips.workspace = true alloy-node-bindings.workspace = true +once_cell.workspace = true tokio.workspace = true diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index bc3f5a06..b873b815 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -4,6 +4,7 @@ use alloy_primitives::Address; use alloy_provider::{PendingTransactionBuilder, Provider, ProviderBuilder, RootProvider}; use alloy_rpc_types_eth::TransactionReceipt; use alloy_signer_local::PrivateKeySigner; +use eigen_logging::{logger::Logger, tracing_logger::TracingLogger}; use eigen_signer::signer::Config; use k256::ecdsa::SigningKey; use reqwest::Url; @@ -26,23 +27,24 @@ pub enum TxManagerError { InvalidUrlError, } -pub struct SimpleTxManager { - //log: logging::Logger, +pub struct SimpleTxManager<'log> { + logger: &'log TracingLogger, gas_limit_multiplier: f64, private_key: String, provider: RootProvider, } -impl SimpleTxManager { +impl<'log> SimpleTxManager<'log> { pub fn new( - //log: logging::Logger, + logger: &'log TracingLogger, gas_limit_multiplier: f64, private_key: &str, rpc_url: &str, - ) -> Result { + ) -> Result, TxManagerError> { let url = Url::parse(rpc_url).map_err(|_| TxManagerError::InvalidUrlError)?; let provider = ProviderBuilder::new().on_http(url); Ok(SimpleTxManager { + logger, gas_limit_multiplier, private_key: private_key.to_string(), provider, @@ -98,11 +100,13 @@ impl SimpleTxManager { tx: &mut TxEip1559, ) -> Result { let signer = self.create_local_signer()?; - let _signed_tx = signer + let _ = signer .sign_transaction(tx) .await .map_err(|_| TxManagerError::SignerError)?; + self.logger.debug("Transaction signed", &[&tx]); + // send transaction and get receipt let pending_tx = self .provider @@ -110,6 +114,9 @@ impl SimpleTxManager { .await .map_err(|_| TxManagerError::SendTxError)?; + self.logger + .debug("Transaction sent. Pending transaction: ", &[&pending_tx]); + // wait for the transaction to be mined SimpleTxManager::wait_for_receipt(pending_tx).await } @@ -140,6 +147,8 @@ impl SimpleTxManager { .await .map_err(|_| TxManagerError::SignerError)?; + self.logger.debug("Transaction signed", &[&tx]); + // send transaction and get receipt let pending_tx = self .provider @@ -147,6 +156,9 @@ impl SimpleTxManager { .await .map_err(|_| TxManagerError::SendTxError)?; + self.logger + .debug("Transaction sent. Pending transaction: ", &[&pending_tx]); + // wait for the transaction to be mined SimpleTxManager::wait_for_receipt(pending_tx).await } @@ -195,19 +207,28 @@ mod tests { use alloy_consensus::TxLegacy; use alloy_node_bindings::Anvil; use alloy_primitives::{bytes, TxKind::Call, U256}; + use eigen_logging::{log_level::LogLevel, logger::Logger, tracing_logger::TracingLogger}; + use once_cell::sync::OnceCell; use tokio; + static TEST_LOGGER: OnceCell = OnceCell::new(); const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; #[tokio::test] async fn test_send_signed_transaction() { + TEST_LOGGER.get_or_init(|| { + TracingLogger::new_text_logger(false, String::from(""), LogLevel::Debug, false) + }); + // Spin up a local Anvil node. // Ensure `anvil` is available in $PATH. let anvil = Anvil::new().try_spawn().unwrap(); let rpc_url: String = anvil.endpoint().parse().unwrap(); // Create a provider. - let simple_tx_manager = SimpleTxManager::new(1.0, PRIVATE_KEY, rpc_url.as_str()).unwrap(); + let logger = TEST_LOGGER.get().unwrap(); + let simple_tx_manager = + SimpleTxManager::new(logger, 1.0, PRIVATE_KEY, rpc_url.as_str()).unwrap(); // Create two users, Alice and Bob. let _alice = anvil.addresses()[0]; From 408f86075cc3a870948af27210e26fe7ae368feb Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 1 Aug 2024 16:56:24 -0300 Subject: [PATCH 51/82] doc in new function --- .../chainio/txmanager/src/simple_tx_manager.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index b873b815..8802c923 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -35,6 +35,22 @@ pub struct SimpleTxManager<'log> { } impl<'log> SimpleTxManager<'log> { + /// Creates a new SimpleTxManager. + /// + /// # Arguments + /// + /// - `logger`: The logger to be used. + /// - `gas_limit_multiplier`: The gas limit multiplier. + /// - `private_key`: The private key of the wallet. + /// - `rpc_url`: The RPC URL. It could be an anvil node or any other node. + /// + /// # Returns + /// + /// - The SimpleTxManager created. + /// + /// # Errors + /// + /// - If the URL is invalid. pub fn new( logger: &'log TracingLogger, gas_limit_multiplier: f64, From 0b89538748491ad8717e0ef8b963b28402a026f1 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 1 Aug 2024 17:32:59 -0300 Subject: [PATCH 52/82] doc links fixed and hello world removed --- crates/chainio/txmanager/src/lib.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/crates/chainio/txmanager/src/lib.rs b/crates/chainio/txmanager/src/lib.rs index 440f4161..0994c738 100644 --- a/crates/chainio/txmanager/src/lib.rs +++ b/crates/chainio/txmanager/src/lib.rs @@ -1,11 +1,7 @@ #![doc( - html_logo_url = "https://github.com/supernovahs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", - issue_tracker_base_url = "https://github.com/supernovahs/eigen-rs/issues/" + html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", + issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] pub mod simple_tx_manager; - -pub fn println_hello() { - println!("Hello, world!"); -} From 2887a0ecc8aa9273185d156bfed9f5a55def3d6e Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 1 Aug 2024 18:36:58 -0300 Subject: [PATCH 53/82] Removen obsolete comment --- crates/chainio/txmanager/src/simple_tx_manager.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 8802c923..1b06c982 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -93,11 +93,6 @@ impl<'log> SimpleTxManager<'log> { /// Sends a EIP1559 transaction. /// - /// Send is used to send a transaction to the Ethereum node. It takes an unsigned/signed transaction - /// and then sends it to the Ethereum node. - /// If you pass in a signed transaction it will ignore the signature - /// and resign the transaction after adding the nonce and gas limit. - /// /// # Arguments /// /// - `tx`: The transaction to be sent. From cb82ed884917929bc9894a9aeaa29c9d4ca0f4a9 Mon Sep 17 00:00:00 2001 From: juanbono Date: Mon, 5 Aug 2024 13:15:47 -0300 Subject: [PATCH 54/82] add initial impl --- .../txmanager/src/simple_tx_manager.rs | 58 +++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 1b06c982..f8549296 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -1,8 +1,9 @@ -use alloy_consensus::{TxEip1559, TxLegacy}; -use alloy_network::{Ethereum, TxSigner}; -use alloy_primitives::Address; +use alloy_consensus::{Transaction, TxEip1559, TxLegacy}; +use alloy_eips::BlockNumberOrTag; +use alloy_network::{Ethereum, TransactionBuilder, TxSigner}; +use alloy_primitives::{Address, TxKind}; use alloy_provider::{PendingTransactionBuilder, Provider, ProviderBuilder, RootProvider}; -use alloy_rpc_types_eth::TransactionReceipt; +use alloy_rpc_types_eth::{TransactionInput, TransactionReceipt, TransactionRequest}; use alloy_signer_local::PrivateKeySigner; use eigen_logging::{logger::Logger, tracing_logger::TracingLogger}; use eigen_signer::signer::Config; @@ -10,6 +11,8 @@ use k256::ecdsa::SigningKey; use reqwest::Url; use thiserror::Error; +static FALLBACK_GAS_TIP_CAP: u128 = 5_000_000_000; + pub type Transport = alloy_transport_http::Http; /// Possible errors raised in Tx Manager @@ -152,6 +155,7 @@ impl<'log> SimpleTxManager<'log> { // TODO: Estimating gas and nonce //m.log.Debug("Estimating gas and nonce") //tx, err := m.estimateGasAndNonce(ctx, tx) + self.estimate_gas_and_nonce(tx); let signer = self.create_local_signer()?; let _signed_tx = signer .sign_transaction(tx) @@ -174,6 +178,52 @@ impl<'log> SimpleTxManager<'log> { SimpleTxManager::wait_for_receipt(pending_tx).await } + async fn estimate_gas_and_nonce(&self, tx: &mut TxLegacy) -> Result<(), TxManagerError> { + let gas_tip_cap = match self.provider.get_max_priority_fee_per_gas().await { + Ok(gas_tip) => gas_tip, + Err(err) => { + self.logger.info("eth_maxPriorityFeePerGas is unsupported by current backend, using fallback gasTipCap", &[err]); + FALLBACK_GAS_TIP_CAP + } + }; + + let header = match self.provider.get_block_by_number(BlockNumberOrTag::Latest, false).await.unwrap() { + Some(block) => block.header, + None => { + self.logger.error("Failed to get latest block header", &[()]); + return Err(TxManagerError::SendTxError); + } + }; + + // 2*baseFee + gasTipCap makes sure that the tx remains includeable for 6 consecutive 100% full blocks. + // see https://www.blocknative.com/blog/eip-1559-fees + let gas_fee_cap = header.base_fee_per_gas.unwrap() * 2 + gas_tip_cap; // TODO: Check unwrap + // TODO: check if gas_fee_cap is always 1. + + let gas_limit = tx.gas_limit(); + + // we only estimate if gas_limit is not already set + if gas_limit == 0 { + let from = self.get_address()?; + let to = match tx.to() { + TxKind::Call(c) => c, + TxKind::Create => return Err(TxManagerError::SendTxError), + }; + let mut tx_request = TransactionRequest::default().to(to).from(from).value(tx.value()).input(TransactionInput::new(tx.input)); + tx_request.set_max_priority_fee_per_gas(gas_tip_cap); + tx_request.set_max_fee_per_gas(gas_fee_cap); + + let gas_limit = self + .provider + .estimate_gas(&tx_request) + .await + .map_err(|_| TxManagerError::SendTxError)?; + + } + + todo!() // TODO: build tx with gas limit + } + /// Waits for the transaction receipt. /// /// This is a wrapper around `PendingTransactionBuilder::get_receipt`. From 8fa6cb7460633a1778e797b4070138a92bd5db32 Mon Sep 17 00:00:00 2001 From: juanbono Date: Mon, 5 Aug 2024 13:20:28 -0300 Subject: [PATCH 55/82] fmt --- .../txmanager/src/simple_tx_manager.rs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index f8549296..60ea3796 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -187,18 +187,23 @@ impl<'log> SimpleTxManager<'log> { } }; - let header = match self.provider.get_block_by_number(BlockNumberOrTag::Latest, false).await.unwrap() { + let header = match self + .provider + .get_block_by_number(BlockNumberOrTag::Latest, false) + .await + .unwrap() + { Some(block) => block.header, None => { - self.logger.error("Failed to get latest block header", &[()]); + self.logger + .error("Failed to get latest block header", &[()]); return Err(TxManagerError::SendTxError); } }; // 2*baseFee + gasTipCap makes sure that the tx remains includeable for 6 consecutive 100% full blocks. - // see https://www.blocknative.com/blog/eip-1559-fees + // see https://www.blocknative.com/blog/eip-1559-fees let gas_fee_cap = header.base_fee_per_gas.unwrap() * 2 + gas_tip_cap; // TODO: Check unwrap - // TODO: check if gas_fee_cap is always 1. let gas_limit = tx.gas_limit(); @@ -209,7 +214,11 @@ impl<'log> SimpleTxManager<'log> { TxKind::Call(c) => c, TxKind::Create => return Err(TxManagerError::SendTxError), }; - let mut tx_request = TransactionRequest::default().to(to).from(from).value(tx.value()).input(TransactionInput::new(tx.input)); + let mut tx_request = TransactionRequest::default() + .to(to) + .from(from) + .value(tx.value()) + .input(TransactionInput::new(tx.input)); tx_request.set_max_priority_fee_per_gas(gas_tip_cap); tx_request.set_max_fee_per_gas(gas_fee_cap); @@ -218,7 +227,6 @@ impl<'log> SimpleTxManager<'log> { .estimate_gas(&tx_request) .await .map_err(|_| TxManagerError::SendTxError)?; - } todo!() // TODO: build tx with gas limit From 405d2b8cb4a9ad0329a89d0062f23c349deac766 Mon Sep 17 00:00:00 2001 From: juanbono Date: Mon, 5 Aug 2024 13:24:06 -0300 Subject: [PATCH 56/82] remove unwrap --- crates/chainio/txmanager/src/simple_tx_manager.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 60ea3796..7e4cb6ed 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -187,14 +187,13 @@ impl<'log> SimpleTxManager<'log> { } }; - let header = match self + let maybe_latest_block = self .provider .get_block_by_number(BlockNumberOrTag::Latest, false) - .await - .unwrap() - { - Some(block) => block.header, - None => { + .await; + let header = match maybe_latest_block { + Ok(Some(block)) => block.header, + _ => { self.logger .error("Failed to get latest block header", &[()]); return Err(TxManagerError::SendTxError); From 09ec76c9982123d70ecb5f007a67eb683beff76f Mon Sep 17 00:00:00 2001 From: juanbono Date: Mon, 5 Aug 2024 13:40:04 -0300 Subject: [PATCH 57/82] refactor --- crates/chainio/txmanager/src/simple_tx_manager.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 7e4cb6ed..541ae960 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -202,7 +202,10 @@ impl<'log> SimpleTxManager<'log> { // 2*baseFee + gasTipCap makes sure that the tx remains includeable for 6 consecutive 100% full blocks. // see https://www.blocknative.com/blog/eip-1559-fees - let gas_fee_cap = header.base_fee_per_gas.unwrap() * 2 + gas_tip_cap; // TODO: Check unwrap + let base_fee = header + .base_fee_per_gas + .ok_or_else(|| TxManagerError::SendTxError)?; + let gas_fee_cap = base_fee * 2 + gas_tip_cap; let gas_limit = tx.gas_limit(); @@ -217,7 +220,7 @@ impl<'log> SimpleTxManager<'log> { .to(to) .from(from) .value(tx.value()) - .input(TransactionInput::new(tx.input)); + .input(TransactionInput::new(tx.input.clone())); tx_request.set_max_priority_fee_per_gas(gas_tip_cap); tx_request.set_max_fee_per_gas(gas_fee_cap); From c5a95f411c480b42473831d0f51cd5d80d9cc574 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Mon, 5 Aug 2024 15:47:08 -0300 Subject: [PATCH 58/82] changes to fee estimation to make it more rustacean --- crates/chainio/txmanager/Cargo.toml | 2 +- crates/chainio/txmanager/src/simple_tx_manager.rs | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index a6595db9..f27a1edd 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -11,6 +11,7 @@ license-file.workspace = true [dependencies] eigen-signer.workspace = true eigen-logging.workspace = true +alloy-eips.workspace = true alloy-consensus.workspace = true alloy-network.workspace = true alloy-primitives.workspace = true @@ -23,7 +24,6 @@ reqwest.workspace = true thiserror.workspace = true [dev-dependencies] -alloy-eips.workspace = true alloy-node-bindings.workspace = true once_cell.workspace = true tokio.workspace = true diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 541ae960..5b0148d7 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -152,10 +152,11 @@ impl<'log> SimpleTxManager<'log> { tx: &mut TxLegacy, ) -> Result { // TODO: It also takes care of gas estimation and adds a buffer to the gas limit + // TODO: Estimating gas and nonce //m.log.Debug("Estimating gas and nonce") - //tx, err := m.estimateGasAndNonce(ctx, tx) - self.estimate_gas_and_nonce(tx); + self.estimate_gas_and_nonce(tx).await?; + let signer = self.create_local_signer()?; let _signed_tx = signer .sign_transaction(tx) @@ -179,13 +180,9 @@ impl<'log> SimpleTxManager<'log> { } async fn estimate_gas_and_nonce(&self, tx: &mut TxLegacy) -> Result<(), TxManagerError> { - let gas_tip_cap = match self.provider.get_max_priority_fee_per_gas().await { - Ok(gas_tip) => gas_tip, - Err(err) => { - self.logger.info("eth_maxPriorityFeePerGas is unsupported by current backend, using fallback gasTipCap", &[err]); - FALLBACK_GAS_TIP_CAP - } - }; + let gas_tip_cap = self.provider.get_max_priority_fee_per_gas().await + .inspect_err(|err| self.logger.info("eth_maxPriorityFeePerGas is unsupported by current backend, using fallback gasTipCap", &[err])) + .unwrap_or(FALLBACK_GAS_TIP_CAP); let maybe_latest_block = self .provider From 8fe701fdeada7af0cf1861c73c0cffcf271d427e Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Mon, 5 Aug 2024 16:10:51 -0300 Subject: [PATCH 59/82] gas_price and gas_limit assigned --- .../txmanager/src/simple_tx_manager.rs | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 5b0148d7..71c487c8 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -184,18 +184,18 @@ impl<'log> SimpleTxManager<'log> { .inspect_err(|err| self.logger.info("eth_maxPriorityFeePerGas is unsupported by current backend, using fallback gasTipCap", &[err])) .unwrap_or(FALLBACK_GAS_TIP_CAP); - let maybe_latest_block = self + let header = self .provider .get_block_by_number(BlockNumberOrTag::Latest, false) - .await; - let header = match maybe_latest_block { - Ok(Some(block)) => block.header, - _ => { + .await + .ok() + .flatten() + .map(|block| block.header) + .ok_or(TxManagerError::SendTxError) + .inspect_err(|_| { self.logger - .error("Failed to get latest block header", &[()]); - return Err(TxManagerError::SendTxError); - } - }; + .error("Failed to get latest block header", &[()]) + })?; // 2*baseFee + gasTipCap makes sure that the tx remains includeable for 6 consecutive 100% full blocks. // see https://www.blocknative.com/blog/eip-1559-fees @@ -204,10 +204,8 @@ impl<'log> SimpleTxManager<'log> { .ok_or_else(|| TxManagerError::SendTxError)?; let gas_fee_cap = base_fee * 2 + gas_tip_cap; - let gas_limit = tx.gas_limit(); - // we only estimate if gas_limit is not already set - if gas_limit == 0 { + if tx.gas_limit() == 0 { let from = self.get_address()?; let to = match tx.to() { TxKind::Call(c) => c, @@ -226,9 +224,13 @@ impl<'log> SimpleTxManager<'log> { .estimate_gas(&tx_request) .await .map_err(|_| TxManagerError::SendTxError)?; - } - todo!() // TODO: build tx with gas limit + let gas_price_multiplied = tx.gas_price as f64 * self.gas_limit_multiplier; + tx.gas_price = gas_price_multiplied as u128; + + tx.gas_limit = gas_limit; + } + Ok(()) } /// Waits for the transaction receipt. From a4e5de22bf1833f1c58565eff5ac668a22e56f6d Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Mon, 5 Aug 2024 16:13:01 -0300 Subject: [PATCH 60/82] debug message --- crates/chainio/txmanager/src/simple_tx_manager.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 71c487c8..5f02c119 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -153,8 +153,8 @@ impl<'log> SimpleTxManager<'log> { ) -> Result { // TODO: It also takes care of gas estimation and adds a buffer to the gas limit - // TODO: Estimating gas and nonce - //m.log.Debug("Estimating gas and nonce") + // Estimating gas and nonce + self.logger.debug("Estimating gas and nonce", &[()]); self.estimate_gas_and_nonce(tx).await?; let signer = self.create_local_signer()?; From 23292f4bf89299da93a32e8f2cc396f088c822ca Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Mon, 5 Aug 2024 16:20:23 -0300 Subject: [PATCH 61/82] obsolete comment removed --- crates/chainio/txmanager/src/simple_tx_manager.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 5f02c119..99c065a5 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -151,8 +151,6 @@ impl<'log> SimpleTxManager<'log> { &self, tx: &mut TxLegacy, ) -> Result { - // TODO: It also takes care of gas estimation and adds a buffer to the gas limit - // Estimating gas and nonce self.logger.debug("Estimating gas and nonce", &[()]); self.estimate_gas_and_nonce(tx).await?; From 36afaf2ced67b386c5dba82562bcb53b27dbb9ca Mon Sep 17 00:00:00 2001 From: juanbono Date: Mon, 5 Aug 2024 17:57:10 -0300 Subject: [PATCH 62/82] multiply gas in all branches --- crates/chainio/txmanager/src/simple_tx_manager.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 99c065a5..99844ed6 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -195,12 +195,12 @@ impl<'log> SimpleTxManager<'log> { .error("Failed to get latest block header", &[()]) })?; - // 2*baseFee + gasTipCap makes sure that the tx remains includeable for 6 consecutive 100% full blocks. + // 2*baseFee + gas_tip_cap makes sure that the tx remains includeable for 6 consecutive 100% full blocks. // see https://www.blocknative.com/blog/eip-1559-fees let base_fee = header .base_fee_per_gas .ok_or_else(|| TxManagerError::SendTxError)?; - let gas_fee_cap = base_fee * 2 + gas_tip_cap; + let gas_fee_cap = 2 * base_fee + gas_tip_cap; // we only estimate if gas_limit is not already set if tx.gas_limit() == 0 { @@ -223,11 +223,11 @@ impl<'log> SimpleTxManager<'log> { .await .map_err(|_| TxManagerError::SendTxError)?; - let gas_price_multiplied = tx.gas_price as f64 * self.gas_limit_multiplier; - tx.gas_price = gas_price_multiplied as u128; - tx.gas_limit = gas_limit; } + let gas_price_multiplied = tx.gas_price as f64 * self.gas_limit_multiplier; + tx.gas_price = gas_price_multiplied as u128; + Ok(()) } From 75d44b06fa90bf3d2579a0f7da7a8862bca601ab Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 7 Aug 2024 12:37:58 -0300 Subject: [PATCH 63/82] Cargo.toml reorganized --- Cargo.toml | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4bad60db..638517d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,30 +4,30 @@ members = [ "crates/chainio/clients/elcontracts/", "crates/chainio/clients/eth/", "crates/chainio/clients/fireblocks/", - "crates/contracts/bindings/", "crates/chainio/txmanager/", "crates/chainio/utils/", - "crates/crypto/bn254/", - "crates/utils/", + "crates/contracts/bindings/", "crates/crypto/bls/", + "crates/crypto/bn254/", "crates/crypto/keystore/", "crates/eigen-cli/", + "crates/logging/", + "crates/metrics/", "crates/metrics/collectors/economic/", "crates/metrics/collectors/rpc_calls/", + "crates/metrics/metrics-derive", "crates/services/avsregistry/", "crates/services/bls_aggregation/", - "crates/metrics/metrics-derive", "crates/services/operatorsinfo/", + "crates/signer/", "crates/types/", - "crates/metrics/", "crates/types/", - "crates/logging/", - "crates/signer/", - "examples/info-operator-service/", - "testing/testing-utils/", + "crates/utils/", + "examples/anvil-utils", "examples/avsregistry-read", "examples/avsregistry-write", - "examples/anvil-utils", + "examples/info-operator-service/", + "testing/testing-utils/", ] resolver = "2" @@ -55,8 +55,8 @@ aws-config = "1.5.4" aws-sdk-kms = "1.37.0" bn254 = { git = "https://github.com/sedaprotocol/bn254" } clap = { version = "4.5.11", features = ["derive"] } -eigen-chainio-utils = { path = "crates/chainio/utils/" } eigen-chainio-txmanager = { path = "crates/chainio/txmanager/" } +eigen-chainio-utils = { path = "crates/chainio/utils/" } eigen-client-avsregistry = { path = "crates/chainio/clients/avsregistry" } eigen-client-elcontracts = { path = "crates/chainio/clients/elcontracts" } eigen-client-eth = { path = "crates/chainio/clients/eth" } @@ -102,8 +102,11 @@ tracing = "0.1.40" tracing-subscriber = { version = "0.3", features = ["json"] } url = "2.5.2" +#misc +parking_lot = "0.12" -# examplesalloy-chains = "0.1.15"#alloyparking_lot = "0.12"#misc +#alloy +alloy-chains = "0.1.15" alloy-consensus = { version = "0.1", default-features = false } alloy-contract = { version = "0.1", default-features = false } alloy-dyn-abi = "0.7.2" From f31207a8cc052b56fce395fbb6c75e097006f406 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 7 Aug 2024 12:44:42 -0300 Subject: [PATCH 64/82] dependencies sorted --- Cargo.toml | 1 + crates/chainio/txmanager/Cargo.toml | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 638517d7..88417915 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,7 @@ eigen-contract-bindings = { path = "crates/contracts/bindings/" } eigen-crypto-bls = { path = "crates/crypto/bls/" } eigen-crypto-bn254 = { path = "crates/crypto/bn254/" } eigen-crypto-keystore = { path = "crates/crypto/keystore/" } +eigen-logging = { path = "crates/logging/" } eigen-signer = { path = "crates/signer/" } eigen-metrics = { version = "0.0.1-alpha", path = "crates/metrics/" } eigen-metrics-collectors-economic = { path = "crates/metrics/collectors/economic" } diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index a6595db9..af3e6184 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "eigen-chainio-txmanager" description = "Eigen Layer Tx Manager" - version.workspace = true edition.workspace = true rust-version.workspace = true @@ -9,8 +8,6 @@ repository.workspace = true license-file.workspace = true [dependencies] -eigen-signer.workspace = true -eigen-logging.workspace = true alloy-consensus.workspace = true alloy-network.workspace = true alloy-primitives.workspace = true @@ -18,6 +15,8 @@ alloy-provider.workspace = true alloy-rpc-types-eth.workspace = true alloy-signer-local.workspace = true alloy-transport-http.workspace = true +eigen-logging.workspace = true +eigen-signer.workspace = true k256.workspace = true reqwest.workspace = true thiserror.workspace = true From abd027791b48eb460210250b3bd96dbf9a69f4bb Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Wed, 7 Aug 2024 13:03:42 -0300 Subject: [PATCH 65/82] Fix warning in dependency used in test --- crates/contracts/bindings/Cargo.toml | 2 +- crates/contracts/bindings/src/generate_bindings.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/contracts/bindings/Cargo.toml b/crates/contracts/bindings/Cargo.toml index dd153e93..c8ce3375 100644 --- a/crates/contracts/bindings/Cargo.toml +++ b/crates/contracts/bindings/Cargo.toml @@ -8,5 +8,5 @@ rust-version.workspace = true repository.workspace = true license-file.workspace = true -[dependencies] +[dev-dependencies] ethers.workspace = true diff --git a/crates/contracts/bindings/src/generate_bindings.rs b/crates/contracts/bindings/src/generate_bindings.rs index cb299d9c..136e2ddb 100644 --- a/crates/contracts/bindings/src/generate_bindings.rs +++ b/crates/contracts/bindings/src/generate_bindings.rs @@ -1,6 +1,5 @@ #[cfg(test)] mod tests { - use ethers::prelude::Abigen; /// Generate rust bindings using ethers From dd4119dc2ef2dd7787345b23b72044d8e2eed9d1 Mon Sep 17 00:00:00 2001 From: juanbono Date: Wed, 7 Aug 2024 17:29:03 -0300 Subject: [PATCH 66/82] add gas estimation to send_legacy_tx --- .../txmanager/src/simple_tx_manager.rs | 66 +++++++++++++------ 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 99844ed6..bf59cb61 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -1,6 +1,6 @@ use alloy_consensus::{Transaction, TxEip1559, TxLegacy}; use alloy_eips::BlockNumberOrTag; -use alloy_network::{Ethereum, TransactionBuilder, TxSigner}; +use alloy_network::{Ethereum, EthereumWallet, TransactionBuilder, TxSigner}; use alloy_primitives::{Address, TxKind}; use alloy_provider::{PendingTransactionBuilder, Provider, ProviderBuilder, RootProvider}; use alloy_rpc_types_eth::{TransactionInput, TransactionReceipt, TransactionRequest}; @@ -153,20 +153,28 @@ impl<'log> SimpleTxManager<'log> { ) -> Result { // Estimating gas and nonce self.logger.debug("Estimating gas and nonce", &[()]); - self.estimate_gas_and_nonce(tx).await?; - let signer = self.create_local_signer()?; - let _signed_tx = signer - .sign_transaction(tx) + let tx = self + .estimate_gas_and_nonce(tx) .await - .map_err(|_| TxManagerError::SignerError)?; + .inspect_err(|err| self.logger.error("Failed to estimate gas", &[err]))?; - self.logger.debug("Transaction signed", &[&tx]); + let signer = self.create_local_signer()?; + let wallet = EthereumWallet::from(signer); + + let signed_tx = tx + .build(&wallet) + .await + .inspect_err(|err| { + self.logger + .error("Failed to build and sign transaction", &[err]) + }) + .map_err(|_| TxManagerError::SendTxError)?; // send transaction and get receipt let pending_tx = self .provider - .send_transaction(tx.clone().into()) + .send_transaction(signed_tx.into()) .await .map_err(|_| TxManagerError::SendTxError)?; @@ -177,7 +185,10 @@ impl<'log> SimpleTxManager<'log> { SimpleTxManager::wait_for_receipt(pending_tx).await } - async fn estimate_gas_and_nonce(&self, tx: &mut TxLegacy) -> Result<(), TxManagerError> { + async fn estimate_gas_and_nonce( + &self, + tx: &TxLegacy, + ) -> Result { let gas_tip_cap = self.provider.get_max_priority_fee_per_gas().await .inspect_err(|err| self.logger.info("eth_maxPriorityFeePerGas is unsupported by current backend, using fallback gasTipCap", &[err])) .unwrap_or(FALLBACK_GAS_TIP_CAP); @@ -197,13 +208,13 @@ impl<'log> SimpleTxManager<'log> { // 2*baseFee + gas_tip_cap makes sure that the tx remains includeable for 6 consecutive 100% full blocks. // see https://www.blocknative.com/blog/eip-1559-fees - let base_fee = header - .base_fee_per_gas - .ok_or_else(|| TxManagerError::SendTxError)?; + let base_fee = header.base_fee_per_gas.ok_or(TxManagerError::SendTxError)?; let gas_fee_cap = 2 * base_fee + gas_tip_cap; + let mut gas_limit = tx.gas_limit(); + let tx_input = tx.input.clone(); // we only estimate if gas_limit is not already set - if tx.gas_limit() == 0 { + if gas_limit == 0 { let from = self.get_address()?; let to = match tx.to() { TxKind::Call(c) => c, @@ -213,22 +224,37 @@ impl<'log> SimpleTxManager<'log> { .to(to) .from(from) .value(tx.value()) - .input(TransactionInput::new(tx.input.clone())); + .input(TransactionInput::new(tx_input.clone())); tx_request.set_max_priority_fee_per_gas(gas_tip_cap); tx_request.set_max_fee_per_gas(gas_fee_cap); - let gas_limit = self + gas_limit = self .provider .estimate_gas(&tx_request) .await .map_err(|_| TxManagerError::SendTxError)?; - - tx.gas_limit = gas_limit; } - let gas_price_multiplied = tx.gas_price as f64 * self.gas_limit_multiplier; - tx.gas_price = gas_price_multiplied as u128; + let gas_price_multiplied = + tx.gas_price().unwrap_or_default() as f64 * self.gas_limit_multiplier; + let gas_price = gas_price_multiplied as u128; + + let to = match tx.to() { + TxKind::Create => return Err(TxManagerError::SendTxError), + TxKind::Call(adress) => adress, + }; - Ok(()) + let new_tx = TransactionRequest::default() + .with_to(to) + .with_value(tx.value()) + .with_gas_limit(gas_limit) + .with_nonce(tx.nonce()) + .with_input(tx_input) + .with_chain_id(tx.chain_id().unwrap_or(1)) + .with_max_priority_fee_per_gas(gas_tip_cap) + .with_max_fee_per_gas(gas_fee_cap) + .with_gas_price(gas_price); + + Ok(new_tx) } /// Waits for the transaction receipt. From de26ce6cbf4ee7a524282691c97cfb9d39075ded Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 8 Aug 2024 11:46:31 -0300 Subject: [PATCH 67/82] fix long line --- crates/chainio/txmanager/src/simple_tx_manager.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index bf59cb61..4ffe1f27 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -190,7 +190,9 @@ impl<'log> SimpleTxManager<'log> { tx: &TxLegacy, ) -> Result { let gas_tip_cap = self.provider.get_max_priority_fee_per_gas().await - .inspect_err(|err| self.logger.info("eth_maxPriorityFeePerGas is unsupported by current backend, using fallback gasTipCap", &[err])) + .inspect_err(|err| + self.logger.info("eth_maxPriorityFeePerGas is unsupported by current backend, using fallback gasTipCap", + &[err])) .unwrap_or(FALLBACK_GAS_TIP_CAP); let header = self From 11e6c1a3ce8ff376d9171f3f0fdadb2448867519 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 8 Aug 2024 12:05:25 -0300 Subject: [PATCH 68/82] doc in estimate_gas_and_nonce --- .../txmanager/src/simple_tx_manager.rs | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 4ffe1f27..0880aa0b 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -185,6 +185,29 @@ impl<'log> SimpleTxManager<'log> { SimpleTxManager::wait_for_receipt(pending_tx).await } + // estimateGasAndNonce we are explicitly implementing this because + // * We want to support legacy transactions (i.e. not dynamic fee) + // * We want to support gas management, i.e. add buffer to gas limit + //func (m *SimpleTxManager) estimateGasAndNonce(ctx context.Context, tx *types.Transaction) (*types.Transaction, error) { + //} + + /// Estimates the gas and nonce for a transaction. + /// + /// # Arguments + /// + /// - `tx`: The transaction for which we want to estimate the gas and nonce. + /// + /// # Returns + /// + /// - The transaction request with the gas and nonce estimated. + /// + /// # Errors + /// + /// - If the transaction request could not sent of gives an error. + /// - If the latest block header could not be retrieved. + /// - If the gas price could not be estimated. + /// - If the gas limit could not be estimated. + /// - If the destination address could not be retrieved. async fn estimate_gas_and_nonce( &self, tx: &TxLegacy, @@ -289,11 +312,7 @@ impl<'log> SimpleTxManager<'log> { func (m *SimpleTxManager) queryReceipt(ctx context.Context, txID wallet.TxID) *types.Receipt { } - // estimateGasAndNonce we are explicitly implementing this because - // * We want to support legacy transactions (i.e. not dynamic fee) - // * We want to support gas management, i.e. add buffer to gas limit - func (m *SimpleTxManager) estimateGasAndNonce(ctx context.Context, tx *types.Transaction) (*types.Transaction, error) { - } + */ } From a0d65afb264c4d051761c9a551f3af0e72b50e17 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 8 Aug 2024 12:06:35 -0300 Subject: [PATCH 69/82] obsolete comment removed --- crates/chainio/txmanager/src/simple_tx_manager.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 0880aa0b..69472511 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -185,12 +185,6 @@ impl<'log> SimpleTxManager<'log> { SimpleTxManager::wait_for_receipt(pending_tx).await } - // estimateGasAndNonce we are explicitly implementing this because - // * We want to support legacy transactions (i.e. not dynamic fee) - // * We want to support gas management, i.e. add buffer to gas limit - //func (m *SimpleTxManager) estimateGasAndNonce(ctx context.Context, tx *types.Transaction) (*types.Transaction, error) { - //} - /// Estimates the gas and nonce for a transaction. /// /// # Arguments From afa1228823e35e6f446cbd59e9bc7b29295b7388 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 8 Aug 2024 12:20:10 -0300 Subject: [PATCH 70/82] another comment removed --- crates/chainio/txmanager/src/simple_tx_manager.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 69472511..8b268862 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -302,11 +302,6 @@ impl<'log> SimpleTxManager<'log> { // this to generate the transaction without actually sending it func (m *SimpleTxManager) GetNoSendTxOpts() (*bind.TransactOpts, error) { } - - func (m *SimpleTxManager) queryReceipt(ctx context.Context, txID wallet.TxID) *types.Receipt { - } - - */ } From fbc30297070d98769b0572f3e6672983f6769960 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 8 Aug 2024 12:22:16 -0300 Subject: [PATCH 71/82] comment removed --- crates/chainio/txmanager/src/simple_tx_manager.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 8b268862..5d5ace35 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -296,13 +296,6 @@ impl<'log> SimpleTxManager<'log> { .await .map_err(|_| TxManagerError::WaitForReceiptError) } - - /* - // GetNoSendTxOpts This generates a noSend TransactOpts so that we can use - // this to generate the transaction without actually sending it - func (m *SimpleTxManager) GetNoSendTxOpts() (*bind.TransactOpts, error) { - } - */ } #[cfg(test)] From 17f5cdb515e357edf4ed6e99a50c7c3d2e52b728 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 8 Aug 2024 12:30:51 -0300 Subject: [PATCH 72/82] alphabetical order in Cargo.toml --- Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 56703e90..7de9aa74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,6 @@ eigen-crypto-bls = { path = "crates/crypto/bls/" } eigen-crypto-bn254 = { path = "crates/crypto/bn254/" } eigen-crypto-keystore = { path = "crates/crypto/keystore/" } eigen-logging = { path = "crates/logging/" } -eigen-signer = { path = "crates/signer/" } eigen-metrics = { version = "0.0.1-alpha", path = "crates/metrics/" } eigen-metrics-collectors-economic = { path = "crates/metrics/collectors/economic" } eigen-metrics-collectors-rpc-calls = { path = "crates/metrics/collectors/rpc_calls" } @@ -74,8 +73,8 @@ eigen-metrics-derive = { path = "crates/metrics/metrics-derive" } eigen-services-avsregistry = { path = "crates/services/avsregistry" } eigen-services-bls_aggregation = { path = "crates/services/bls_aggregation" } eigen-services-operatorsinfo = { path = "crates/services/operatorsinfo" } +eigen-signer = { path = "crates/signer/" } eigen-testing-utils = { path = "testing/testing-utils" } -eigen-logging = {path = "crates/logging"} eigen-types = { path = "crates/types/" } eigen-utils = { path = "crates/utils/" } eth-keystore = "0.5.0" From 55ba173eb59dbb397643098704507384ed6450a9 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 8 Aug 2024 13:15:45 -0300 Subject: [PATCH 73/82] Adding test for TxEip1559 tx --- .../txmanager/src/simple_tx_manager.rs | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 5d5ace35..5f2f3374 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -301,9 +301,10 @@ impl<'log> SimpleTxManager<'log> { #[cfg(test)] mod tests { use super::SimpleTxManager; - use alloy_consensus::TxLegacy; + use alloy_consensus::{TxEip1559, TxLegacy}; use alloy_node_bindings::Anvil; - use alloy_primitives::{bytes, TxKind::Call, U256}; + use alloy_primitives::{bytes, Address, TxKind::Call, U256}; + use alloy_rpc_types_eth::AccessList; use eigen_logging::{log_level::LogLevel, logger::Logger, tracing_logger::TracingLogger}; use once_cell::sync::OnceCell; use tokio; @@ -311,8 +312,7 @@ mod tests { static TEST_LOGGER: OnceCell = OnceCell::new(); const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; - #[tokio::test] - async fn test_send_signed_transaction() { + fn setup_and_get_dest_address<'log>() -> (SimpleTxManager<'log>, Address) { TEST_LOGGER.get_or_init(|| { TracingLogger::new_text_logger(false, String::from(""), LogLevel::Debug, false) }); @@ -330,7 +330,14 @@ mod tests { // Create two users, Alice and Bob. let _alice = anvil.addresses()[0]; let bob = anvil.addresses()[1]; + (simple_tx_manager, bob) + } + #[tokio::test] + async fn test_send_signed_legacy_transaction() { + let (simple_tx_manager, bob) = setup_and_get_dest_address(); + + // Test 1: legacy tx let mut tx = TxLegacy { to: Call(bob), value: U256::from(1_000_000_000), @@ -347,5 +354,28 @@ mod tests { println!("Transaction mined in block: {}", block_number); assert!(block_number > 0); assert_eq!(receipt.to, Some(bob)); + + // Test 2: EIP1559 tx + let mut tx_eip1559 = TxEip1559 { + to: Call(bob), + value: U256::from(1_000_000_000), + nonce: 0, + input: bytes!(), + chain_id: 31337, + gas_limit: 2_000_000, + max_fee_per_gas: 2_000_000, + max_priority_fee_per_gas: 200, + access_list: AccessList::default(), + }; + + // send transaction and wait for receipt + let receipt = simple_tx_manager + .send_eip1559_tx(&mut tx_eip1559) + .await + .unwrap(); + let block_number = receipt.block_number.unwrap(); + println!("Transaction mined in block: {}", block_number); + assert!(block_number > 0); + assert_eq!(receipt.to, Some(bob)); } } From e1eb4f39ee6e6609a210c3683b6f262a1e72fd20 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 8 Aug 2024 13:34:41 -0300 Subject: [PATCH 74/82] adding logging operations --- .../txmanager/src/simple_tx_manager.rs | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 5f2f3374..599b71da 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -60,7 +60,9 @@ impl<'log> SimpleTxManager<'log> { private_key: &str, rpc_url: &str, ) -> Result, TxManagerError> { - let url = Url::parse(rpc_url).map_err(|_| TxManagerError::InvalidUrlError)?; + let url = Url::parse(rpc_url) + .inspect_err(|err| logger.error("Failed to parse url", &[err])) + .map_err(|_| TxManagerError::InvalidUrlError)?; let provider = ProviderBuilder::new().on_http(url); Ok(SimpleTxManager { logger, @@ -81,6 +83,7 @@ impl<'log> SimpleTxManager<'log> { /// - If the private key is invalid. pub fn get_address(&self) -> Result { let private_key_signing_key = SigningKey::from_slice(self.private_key.as_bytes()) + .inspect_err(|err| self.logger.error("Failed to parse private key", &[err])) .map_err(|_| TxManagerError::AddressError)?; Ok(Address::from_private_key(&private_key_signing_key)) } @@ -91,7 +94,9 @@ impl<'log> SimpleTxManager<'log> { fn create_local_signer(&self) -> Result { let config = Config::PrivateKey(self.private_key.clone()); - Config::signer_from_config(config).map_err(|_| TxManagerError::SignerError) + Config::signer_from_config(config) + .inspect_err(|err| self.logger.error("Failed to create signer", &[err])) + .map_err(|_| TxManagerError::SignerError) } /// Sends a EIP1559 transaction. @@ -117,6 +122,7 @@ impl<'log> SimpleTxManager<'log> { let _ = signer .sign_transaction(tx) .await + .inspect_err(|err| self.logger.error("Failed to sign transaction", &[err])) .map_err(|_| TxManagerError::SignerError)?; self.logger.debug("Transaction signed", &[&tx]); @@ -126,13 +132,14 @@ impl<'log> SimpleTxManager<'log> { .provider .send_transaction(tx.clone().into()) .await + .inspect_err(|err| self.logger.error("Failed to send transaction", &[err])) .map_err(|_| TxManagerError::SendTxError)?; self.logger .debug("Transaction sent. Pending transaction: ", &[&pending_tx]); // wait for the transaction to be mined - SimpleTxManager::wait_for_receipt(pending_tx).await + SimpleTxManager::wait_for_receipt(self, pending_tx).await } /// Send is used to send a transaction to the Ethereum node. It takes an unsigned/signed transaction @@ -176,13 +183,14 @@ impl<'log> SimpleTxManager<'log> { .provider .send_transaction(signed_tx.into()) .await + .inspect_err(|err| self.logger.error("Failed to get receipt", &[err])) .map_err(|_| TxManagerError::SendTxError)?; self.logger .debug("Transaction sent. Pending transaction: ", &[&pending_tx]); // wait for the transaction to be mined - SimpleTxManager::wait_for_receipt(pending_tx).await + SimpleTxManager::wait_for_receipt(self, pending_tx).await } /// Estimates the gas and nonce for a transaction. @@ -289,11 +297,13 @@ impl<'log> SimpleTxManager<'log> { /// - The block number in which the transaction was included. /// - `None` if the transaction was not included in a block or an error ocurred. pub async fn wait_for_receipt( + &self, pending_tx: PendingTransactionBuilder<'_, Transport, Ethereum>, ) -> Result { pending_tx .get_receipt() .await + .inspect_err(|err| self.logger.error("Failed to get receipt", &[err])) .map_err(|_| TxManagerError::WaitForReceiptError) } } @@ -312,7 +322,8 @@ mod tests { static TEST_LOGGER: OnceCell = OnceCell::new(); const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; - fn setup_and_get_dest_address<'log>() -> (SimpleTxManager<'log>, Address) { + #[tokio::test] + async fn test_send_signed_legacy_transaction() { TEST_LOGGER.get_or_init(|| { TracingLogger::new_text_logger(false, String::from(""), LogLevel::Debug, false) }); @@ -330,12 +341,6 @@ mod tests { // Create two users, Alice and Bob. let _alice = anvil.addresses()[0]; let bob = anvil.addresses()[1]; - (simple_tx_manager, bob) - } - - #[tokio::test] - async fn test_send_signed_legacy_transaction() { - let (simple_tx_manager, bob) = setup_and_get_dest_address(); // Test 1: legacy tx let mut tx = TxLegacy { @@ -356,6 +361,7 @@ mod tests { assert_eq!(receipt.to, Some(bob)); // Test 2: EIP1559 tx + /* let mut tx_eip1559 = TxEip1559 { to: Call(bob), value: U256::from(1_000_000_000), @@ -377,5 +383,6 @@ mod tests { println!("Transaction mined in block: {}", block_number); assert!(block_number > 0); assert_eq!(receipt.to, Some(bob)); + */ } } From 5d14e3d9532526460b86df32186e00b480a23bd3 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 8 Aug 2024 14:50:42 -0300 Subject: [PATCH 75/82] nonce changed --- crates/chainio/txmanager/src/simple_tx_manager.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 599b71da..32b92566 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -360,12 +360,12 @@ mod tests { assert!(block_number > 0); assert_eq!(receipt.to, Some(bob)); - // Test 2: EIP1559 tx /* + // Test 2: EIP1559 tx let mut tx_eip1559 = TxEip1559 { to: Call(bob), value: U256::from(1_000_000_000), - nonce: 0, + nonce: 100, input: bytes!(), chain_id: 31337, gas_limit: 2_000_000, From 808327761b8ffaf51dac50df02a0f7f9581e0d95 Mon Sep 17 00:00:00 2001 From: juanbono Date: Thu, 8 Aug 2024 15:57:24 -0300 Subject: [PATCH 76/82] use transactionRequest instead of concrete tx --- .../txmanager/src/simple_tx_manager.rs | 227 +++++++++++++++--- 1 file changed, 188 insertions(+), 39 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 32b92566..d2a53508 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -1,6 +1,6 @@ use alloy_consensus::{Transaction, TxEip1559, TxLegacy}; use alloy_eips::BlockNumberOrTag; -use alloy_network::{Ethereum, EthereumWallet, TransactionBuilder, TxSigner}; +use alloy_network::{Ethereum, EthereumWallet, TransactionBuilder}; use alloy_primitives::{Address, TxKind}; use alloy_provider::{PendingTransactionBuilder, Provider, ProviderBuilder, RootProvider}; use alloy_rpc_types_eth::{TransactionInput, TransactionReceipt, TransactionRequest}; @@ -118,19 +118,32 @@ impl<'log> SimpleTxManager<'log> { &self, tx: &mut TxEip1559, ) -> Result { + // Estimating gas and nonce + self.logger.debug("Estimating gas and nonce", &[()]); + + let tx = self + .estimate_gas_and_nonce(tx) + .await + .inspect_err(|err| self.logger.error("Failed to estimate gas", &[err]))?; + let signer = self.create_local_signer()?; - let _ = signer - .sign_transaction(tx) + let wallet = EthereumWallet::from(signer); + + let signed_tx = tx + .build(&wallet) .await - .inspect_err(|err| self.logger.error("Failed to sign transaction", &[err])) - .map_err(|_| TxManagerError::SignerError)?; + .inspect_err(|err| { + self.logger + .error("Failed to build and sign transaction", &[err]) + }) + .map_err(|_| TxManagerError::SendTxError)?; - self.logger.debug("Transaction signed", &[&tx]); + self.logger.debug("Transaction signed", &[&signed_tx]); // send transaction and get receipt let pending_tx = self .provider - .send_transaction(tx.clone().into()) + .send_transaction(signed_tx.into()) .await .inspect_err(|err| self.logger.error("Failed to send transaction", &[err])) .map_err(|_| TxManagerError::SendTxError)?; @@ -193,6 +206,46 @@ impl<'log> SimpleTxManager<'log> { SimpleTxManager::wait_for_receipt(self, pending_tx).await } + + pub async fn send_tx( + &self, + tx: &mut TransactionRequest, + ) -> Result { + // Estimating gas and nonce + self.logger.debug("Estimating gas and nonce", &[()]); + + let tx = self + .estimate_gas_and_nonce_2(tx) + .await + .inspect_err(|err| self.logger.error("Failed to estimate gas", &[err]))?; + + let signer = self.create_local_signer()?; + let wallet = EthereumWallet::from(signer); + + let signed_tx = tx + .build(&wallet) + .await + .inspect_err(|err| { + self.logger + .error("Failed to build and sign transaction", &[err]) + }) + .map_err(|_| TxManagerError::SendTxError)?; + + // send transaction and get receipt + let pending_tx = self + .provider + .send_transaction(signed_tx.into()) + .await + .inspect_err(|err| self.logger.error("Failed to get receipt", &[err])) + .map_err(|_| TxManagerError::SendTxError)?; + + self.logger + .debug("Transaction sent. Pending transaction: ", &[&pending_tx]); + + // wait for the transaction to be mined + SimpleTxManager::wait_for_receipt(self, pending_tx).await + } + /// Estimates the gas and nonce for a transaction. /// /// # Arguments @@ -210,9 +263,9 @@ impl<'log> SimpleTxManager<'log> { /// - If the gas price could not be estimated. /// - If the gas limit could not be estimated. /// - If the destination address could not be retrieved. - async fn estimate_gas_and_nonce( + async fn estimate_gas_and_nonce( &self, - tx: &TxLegacy, + tx: &T, ) -> Result { let gas_tip_cap = self.provider.get_max_priority_fee_per_gas().await .inspect_err(|err| @@ -239,7 +292,7 @@ impl<'log> SimpleTxManager<'log> { let gas_fee_cap = 2 * base_fee + gas_tip_cap; let mut gas_limit = tx.gas_limit(); - let tx_input = tx.input.clone(); + let tx_input = tx.input().to_vec(); // we only estimate if gas_limit is not already set if gas_limit == 0 { let from = self.get_address()?; @@ -251,7 +304,7 @@ impl<'log> SimpleTxManager<'log> { .to(to) .from(from) .value(tx.value()) - .input(TransactionInput::new(tx_input.clone())); + .input(TransactionInput::new(tx_input.clone().into())); tx_request.set_max_priority_fee_per_gas(gas_tip_cap); tx_request.set_max_fee_per_gas(gas_fee_cap); @@ -284,6 +337,80 @@ impl<'log> SimpleTxManager<'log> { Ok(new_tx) } + async fn estimate_gas_and_nonce_2( + &self, + tx: &TransactionRequest, + ) -> Result { + let gas_tip_cap = self.provider.get_max_priority_fee_per_gas().await + .inspect_err(|err| + self.logger.info("eth_maxPriorityFeePerGas is unsupported by current backend, using fallback gasTipCap", + &[err])) + .unwrap_or(FALLBACK_GAS_TIP_CAP); + + let header = self + .provider + .get_block_by_number(BlockNumberOrTag::Latest, false) + .await + .ok() + .flatten() + .map(|block| block.header) + .ok_or(TxManagerError::SendTxError) + .inspect_err(|_| { + self.logger + .error("Failed to get latest block header", &[()]) + })?; + + // 2*baseFee + gas_tip_cap makes sure that the tx remains includeable for 6 consecutive 100% full blocks. + // see https://www.blocknative.com/blog/eip-1559-fees + let base_fee = header.base_fee_per_gas.ok_or(TxManagerError::SendTxError)?; + let gas_fee_cap = 2 * base_fee + gas_tip_cap; + + let mut gas_limit = tx.gas_limit(); + let tx_input = tx.input().unwrap_or_default().to_vec(); + // we only estimate if gas_limit is not already set + if let Some(0) = gas_limit { + let from = self.get_address()?; + let to = match tx.to() { + Some(c) => c, + None => return Err(TxManagerError::SendTxError), + }; + let mut tx_request = TransactionRequest::default() + .to(to) + .from(from) + .value(tx.value().unwrap_or_default()) + .input(TransactionInput::new(tx_input.clone().into())); + tx_request.set_max_priority_fee_per_gas(gas_tip_cap); + tx_request.set_max_fee_per_gas(gas_fee_cap); + + gas_limit = Some(self + .provider + .estimate_gas(&tx_request) + .await + .map_err(|_| TxManagerError::SendTxError)?); + } + let gas_price_multiplied = + tx.gas_price().unwrap_or_default() as f64 * self.gas_limit_multiplier; + let gas_price = gas_price_multiplied as u128; + + let to = match tx.to() { + None => return Err(TxManagerError::SendTxError), + Some(adress) => adress, + }; + + let new_tx = TransactionRequest::default() + .with_to(to) + .with_value(tx.value().unwrap_or_default()) + .with_gas_limit(gas_limit.unwrap_or_default()) + .with_nonce(tx.nonce().unwrap_or_default()) + .with_input(tx_input) + .with_chain_id(tx.chain_id().unwrap_or(1)) + .with_max_priority_fee_per_gas(gas_tip_cap) + .with_max_fee_per_gas(gas_fee_cap) + .with_gas_price(gas_price); + + Ok(new_tx) + } + /// Waits for the transaction receipt. /// /// This is a wrapper around `PendingTransactionBuilder::get_receipt`. @@ -312,9 +439,10 @@ impl<'log> SimpleTxManager<'log> { mod tests { use super::SimpleTxManager; use alloy_consensus::{TxEip1559, TxLegacy}; + use alloy_network::TransactionBuilder; use alloy_node_bindings::Anvil; use alloy_primitives::{bytes, Address, TxKind::Call, U256}; - use alloy_rpc_types_eth::AccessList; + use alloy_rpc_types_eth::{AccessList, TransactionRequest}; use eigen_logging::{log_level::LogLevel, logger::Logger, tracing_logger::TracingLogger}; use once_cell::sync::OnceCell; use tokio; @@ -322,8 +450,47 @@ mod tests { static TEST_LOGGER: OnceCell = OnceCell::new(); const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; + // #[tokio::test] + // async fn test_send_signed_legacy_transaction() { + // TEST_LOGGER.get_or_init(|| { + // TracingLogger::new_text_logger(false, String::from(""), LogLevel::Debug, false) + // }); + + // // Spin up a local Anvil node. + // // Ensure `anvil` is available in $PATH. + // let anvil = Anvil::new().try_spawn().unwrap(); + // let rpc_url: String = anvil.endpoint().parse().unwrap(); + + // // Create a provider. + // let logger = TEST_LOGGER.get().unwrap(); + // let simple_tx_manager = + // SimpleTxManager::new(logger, 1.0, PRIVATE_KEY, rpc_url.as_str()).unwrap(); + + // // Create two users, Alice and Bob. + // let _alice = anvil.addresses()[0]; + // let bob = anvil.addresses()[1]; + + // // Test 1: legacy tx + // let mut tx = TxLegacy { + // to: Call(bob), + // value: U256::from(1_000_000_000), + // gas_limit: 2_000_000, + // nonce: 0, + // gas_price: 21_000_000_000, + // input: bytes!(), + // chain_id: Some(31337), + // }; + + // //// send transaction and wait for receipt + // let receipt = simple_tx_manager.send_legacy_tx(&mut tx).await.unwrap(); + // let block_number = receipt.block_number.unwrap(); + // println!("Transaction mined in block: {}", block_number); + // assert!(block_number > 0); + // assert_eq!(receipt.to, Some(bob)); + // } + #[tokio::test] - async fn test_send_signed_legacy_transaction() { + async fn test_send_signed_eip1559_transaction() { TEST_LOGGER.get_or_init(|| { TracingLogger::new_text_logger(false, String::from(""), LogLevel::Debug, false) }); @@ -342,38 +509,21 @@ mod tests { let _alice = anvil.addresses()[0]; let bob = anvil.addresses()[1]; - // Test 1: legacy tx - let mut tx = TxLegacy { - to: Call(bob), - value: U256::from(1_000_000_000), - gas_limit: 2_000_000, - nonce: 0, - gas_price: 21_000_000_000, - input: bytes!(), - chain_id: Some(31337), - }; - - //// send transaction and wait for receipt - let receipt = simple_tx_manager.send_legacy_tx(&mut tx).await.unwrap(); - let block_number = receipt.block_number.unwrap(); - println!("Transaction mined in block: {}", block_number); - assert!(block_number > 0); - assert_eq!(receipt.to, Some(bob)); - - /* - // Test 2: EIP1559 tx let mut tx_eip1559 = TxEip1559 { to: Call(bob), - value: U256::from(1_000_000_000), - nonce: 100, + value: U256::from(100), + nonce: 0, input: bytes!(), chain_id: 31337, - gas_limit: 2_000_000, - max_fee_per_gas: 2_000_000, - max_priority_fee_per_gas: 200, + gas_limit: 21_000_000, + max_fee_per_gas: 20_000_000_000_000, + max_priority_fee_per_gas: 1_000_000_000, access_list: AccessList::default(), }; + let mut tx_request: TransactionRequest = tx_eip1559.clone().into(); + tx_request.set_gas_price(2100000000000); + println!("Transaction request: {:?}", tx_request); // send transaction and wait for receipt let receipt = simple_tx_manager .send_eip1559_tx(&mut tx_eip1559) @@ -383,6 +533,5 @@ mod tests { println!("Transaction mined in block: {}", block_number); assert!(block_number > 0); assert_eq!(receipt.to, Some(bob)); - */ } } From ea40e21676c724534352daa4b7f995f2bf77e089 Mon Sep 17 00:00:00 2001 From: juanbono Date: Thu, 8 Aug 2024 18:08:53 -0300 Subject: [PATCH 77/82] fix test --- .../txmanager/src/simple_tx_manager.rs | 109 +++++++++--------- 1 file changed, 53 insertions(+), 56 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index d2a53508..b4df1ab1 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -206,7 +206,6 @@ impl<'log> SimpleTxManager<'log> { SimpleTxManager::wait_for_receipt(self, pending_tx).await } - pub async fn send_tx( &self, tx: &mut TransactionRequest, @@ -382,11 +381,12 @@ impl<'log> SimpleTxManager<'log> { tx_request.set_max_priority_fee_per_gas(gas_tip_cap); tx_request.set_max_fee_per_gas(gas_fee_cap); - gas_limit = Some(self - .provider - .estimate_gas(&tx_request) - .await - .map_err(|_| TxManagerError::SendTxError)?); + gas_limit = Some( + self.provider + .estimate_gas(&tx_request) + .await + .map_err(|_| TxManagerError::SendTxError)?, + ); } let gas_price_multiplied = tx.gas_price().unwrap_or_default() as f64 * self.gas_limit_multiplier; @@ -450,47 +450,48 @@ mod tests { static TEST_LOGGER: OnceCell = OnceCell::new(); const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; - // #[tokio::test] - // async fn test_send_signed_legacy_transaction() { - // TEST_LOGGER.get_or_init(|| { - // TracingLogger::new_text_logger(false, String::from(""), LogLevel::Debug, false) - // }); - - // // Spin up a local Anvil node. - // // Ensure `anvil` is available in $PATH. - // let anvil = Anvil::new().try_spawn().unwrap(); - // let rpc_url: String = anvil.endpoint().parse().unwrap(); - - // // Create a provider. - // let logger = TEST_LOGGER.get().unwrap(); - // let simple_tx_manager = - // SimpleTxManager::new(logger, 1.0, PRIVATE_KEY, rpc_url.as_str()).unwrap(); - - // // Create two users, Alice and Bob. - // let _alice = anvil.addresses()[0]; - // let bob = anvil.addresses()[1]; - - // // Test 1: legacy tx - // let mut tx = TxLegacy { - // to: Call(bob), - // value: U256::from(1_000_000_000), - // gas_limit: 2_000_000, - // nonce: 0, - // gas_price: 21_000_000_000, - // input: bytes!(), - // chain_id: Some(31337), - // }; - - // //// send transaction and wait for receipt - // let receipt = simple_tx_manager.send_legacy_tx(&mut tx).await.unwrap(); - // let block_number = receipt.block_number.unwrap(); - // println!("Transaction mined in block: {}", block_number); - // assert!(block_number > 0); - // assert_eq!(receipt.to, Some(bob)); - // } + #[tokio::test] + async fn test_send_transaction_from_legacy() { + TEST_LOGGER.get_or_init(|| { + TracingLogger::new_text_logger(false, String::from(""), LogLevel::Debug, false) + }); + + // Spin up a local Anvil node. + // Ensure `anvil` is available in $PATH. + let anvil = Anvil::new().try_spawn().unwrap(); + let rpc_url: String = anvil.endpoint().parse().unwrap(); + + // Create a provider. + let logger = TEST_LOGGER.get().unwrap(); + let simple_tx_manager = + SimpleTxManager::new(logger, 1.0, PRIVATE_KEY, rpc_url.as_str()).unwrap(); + + // Create two users, Alice and Bob. + let _alice = anvil.addresses()[0]; + let bob = anvil.addresses()[1]; + + // Test 1: legacy tx + let tx = TxLegacy { + to: Call(bob), + value: U256::from(1_000_000_000), + gas_limit: 2_000_000, + nonce: 0, + gas_price: 21_000_000_000, + input: bytes!(), + chain_id: Some(31337), + }; + + let mut tx_request: TransactionRequest = tx.clone().into(); + //// send transaction and wait for receipt + let receipt = simple_tx_manager.send_tx(&mut tx_request).await.unwrap(); + let block_number = receipt.block_number.unwrap(); + println!("Transaction mined in block: {}", block_number); + assert!(block_number > 0); + assert_eq!(receipt.to, Some(bob)); + } #[tokio::test] - async fn test_send_signed_eip1559_transaction() { + async fn test_send_transaction_from_eip1559() { TEST_LOGGER.get_or_init(|| { TracingLogger::new_text_logger(false, String::from(""), LogLevel::Debug, false) }); @@ -509,26 +510,22 @@ mod tests { let _alice = anvil.addresses()[0]; let bob = anvil.addresses()[1]; - let mut tx_eip1559 = TxEip1559 { + let tx_eip1559 = TxEip1559 { to: Call(bob), value: U256::from(100), - nonce: 0, + nonce: 100, input: bytes!(), chain_id: 31337, - gas_limit: 21_000_000, - max_fee_per_gas: 20_000_000_000_000, - max_priority_fee_per_gas: 1_000_000_000, + gas_limit: 210000, + max_fee_per_gas: 2_000_000_000, + max_priority_fee_per_gas: 1_000_000, access_list: AccessList::default(), }; let mut tx_request: TransactionRequest = tx_eip1559.clone().into(); - tx_request.set_gas_price(2100000000000); - println!("Transaction request: {:?}", tx_request); + tx_request.set_gas_price(21_000_000_000); // send transaction and wait for receipt - let receipt = simple_tx_manager - .send_eip1559_tx(&mut tx_eip1559) - .await - .unwrap(); + let receipt = simple_tx_manager.send_tx(&mut tx_request).await.unwrap(); let block_number = receipt.block_number.unwrap(); println!("Transaction mined in block: {}", block_number); assert!(block_number > 0); From 3803cefc5ddad73627c4d01449905f0661d7adec Mon Sep 17 00:00:00 2001 From: juanbono Date: Thu, 8 Aug 2024 20:06:19 -0300 Subject: [PATCH 78/82] use TransactionRequest in test --- .../txmanager/src/simple_tx_manager.rs | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index b4df1ab1..a75a46c8 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -438,11 +438,11 @@ impl<'log> SimpleTxManager<'log> { #[cfg(test)] mod tests { use super::SimpleTxManager; - use alloy_consensus::{TxEip1559, TxLegacy}; + use alloy_consensus::TxLegacy; use alloy_network::TransactionBuilder; use alloy_node_bindings::Anvil; - use alloy_primitives::{bytes, Address, TxKind::Call, U256}; - use alloy_rpc_types_eth::{AccessList, TransactionRequest}; + use alloy_primitives::{bytes, TxKind::Call, U256}; + use alloy_rpc_types_eth::TransactionRequest; use eigen_logging::{log_level::LogLevel, logger::Logger, tracing_logger::TracingLogger}; use once_cell::sync::OnceCell; use tokio; @@ -510,22 +510,18 @@ mod tests { let _alice = anvil.addresses()[0]; let bob = anvil.addresses()[1]; - let tx_eip1559 = TxEip1559 { - to: Call(bob), - value: U256::from(100), - nonce: 100, - input: bytes!(), - chain_id: 31337, - gas_limit: 210000, - max_fee_per_gas: 2_000_000_000, - max_priority_fee_per_gas: 1_000_000, - access_list: AccessList::default(), - }; + let mut tx = TransactionRequest::default() + .with_to(bob) + .with_nonce(0) + .with_chain_id(anvil.chain_id()) + .with_value(U256::from(100)) + .with_gas_limit(21_000) + .with_max_priority_fee_per_gas(1_000_000_000) + .with_max_fee_per_gas(20_000_000_000); - let mut tx_request: TransactionRequest = tx_eip1559.clone().into(); - tx_request.set_gas_price(21_000_000_000); + tx.set_gas_price(21_000_000_000); // send transaction and wait for receipt - let receipt = simple_tx_manager.send_tx(&mut tx_request).await.unwrap(); + let receipt = simple_tx_manager.send_tx(&mut tx).await.unwrap(); let block_number = receipt.block_number.unwrap(); println!("Transaction mined in block: {}", block_number); assert!(block_number > 0); From a0a72d097b504bb6fdaf5d456371e752c103bfce Mon Sep 17 00:00:00 2001 From: juanbono Date: Fri, 9 Aug 2024 07:43:06 -0300 Subject: [PATCH 79/82] remove unused functions after refactor --- .../txmanager/src/simple_tx_manager.rs | 176 +----------------- 1 file changed, 3 insertions(+), 173 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index a75a46c8..9ae72027 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -1,7 +1,6 @@ -use alloy_consensus::{Transaction, TxEip1559, TxLegacy}; use alloy_eips::BlockNumberOrTag; use alloy_network::{Ethereum, EthereumWallet, TransactionBuilder}; -use alloy_primitives::{Address, TxKind}; +use alloy_primitives::Address; use alloy_provider::{PendingTransactionBuilder, Provider, ProviderBuilder, RootProvider}; use alloy_rpc_types_eth::{TransactionInput, TransactionReceipt, TransactionRequest}; use alloy_signer_local::PrivateKeySigner; @@ -99,62 +98,6 @@ impl<'log> SimpleTxManager<'log> { .map_err(|_| TxManagerError::SignerError) } - /// Sends a EIP1559 transaction. - /// - /// # Arguments - /// - /// - `tx`: The transaction to be sent. - /// - /// # Returns - /// - /// - The transaction receipt. - /// - /// # Errors - /// - /// - If the transaction could not be signed. - /// - If the transaction could not be sent. - /// - If the transaction could not be mined. - pub async fn send_eip1559_tx( - &self, - tx: &mut TxEip1559, - ) -> Result { - // Estimating gas and nonce - self.logger.debug("Estimating gas and nonce", &[()]); - - let tx = self - .estimate_gas_and_nonce(tx) - .await - .inspect_err(|err| self.logger.error("Failed to estimate gas", &[err]))?; - - let signer = self.create_local_signer()?; - let wallet = EthereumWallet::from(signer); - - let signed_tx = tx - .build(&wallet) - .await - .inspect_err(|err| { - self.logger - .error("Failed to build and sign transaction", &[err]) - }) - .map_err(|_| TxManagerError::SendTxError)?; - - self.logger.debug("Transaction signed", &[&signed_tx]); - - // send transaction and get receipt - let pending_tx = self - .provider - .send_transaction(signed_tx.into()) - .await - .inspect_err(|err| self.logger.error("Failed to send transaction", &[err])) - .map_err(|_| TxManagerError::SendTxError)?; - - self.logger - .debug("Transaction sent. Pending transaction: ", &[&pending_tx]); - - // wait for the transaction to be mined - SimpleTxManager::wait_for_receipt(self, pending_tx).await - } - /// Send is used to send a transaction to the Ethereum node. It takes an unsigned/signed transaction /// and then sends it to the Ethereum node. /// If you pass in a signed transaction it will ignore the signature @@ -167,45 +110,6 @@ impl<'log> SimpleTxManager<'log> { /// # Returns /// /// - The transaction receipt. - pub async fn send_legacy_tx( - &self, - tx: &mut TxLegacy, - ) -> Result { - // Estimating gas and nonce - self.logger.debug("Estimating gas and nonce", &[()]); - - let tx = self - .estimate_gas_and_nonce(tx) - .await - .inspect_err(|err| self.logger.error("Failed to estimate gas", &[err]))?; - - let signer = self.create_local_signer()?; - let wallet = EthereumWallet::from(signer); - - let signed_tx = tx - .build(&wallet) - .await - .inspect_err(|err| { - self.logger - .error("Failed to build and sign transaction", &[err]) - }) - .map_err(|_| TxManagerError::SendTxError)?; - - // send transaction and get receipt - let pending_tx = self - .provider - .send_transaction(signed_tx.into()) - .await - .inspect_err(|err| self.logger.error("Failed to get receipt", &[err])) - .map_err(|_| TxManagerError::SendTxError)?; - - self.logger - .debug("Transaction sent. Pending transaction: ", &[&pending_tx]); - - // wait for the transaction to be mined - SimpleTxManager::wait_for_receipt(self, pending_tx).await - } - pub async fn send_tx( &self, tx: &mut TransactionRequest, @@ -214,7 +118,7 @@ impl<'log> SimpleTxManager<'log> { self.logger.debug("Estimating gas and nonce", &[()]); let tx = self - .estimate_gas_and_nonce_2(tx) + .estimate_gas_and_nonce(tx) .await .inspect_err(|err| self.logger.error("Failed to estimate gas", &[err]))?; @@ -262,81 +166,7 @@ impl<'log> SimpleTxManager<'log> { /// - If the gas price could not be estimated. /// - If the gas limit could not be estimated. /// - If the destination address could not be retrieved. - async fn estimate_gas_and_nonce( - &self, - tx: &T, - ) -> Result { - let gas_tip_cap = self.provider.get_max_priority_fee_per_gas().await - .inspect_err(|err| - self.logger.info("eth_maxPriorityFeePerGas is unsupported by current backend, using fallback gasTipCap", - &[err])) - .unwrap_or(FALLBACK_GAS_TIP_CAP); - - let header = self - .provider - .get_block_by_number(BlockNumberOrTag::Latest, false) - .await - .ok() - .flatten() - .map(|block| block.header) - .ok_or(TxManagerError::SendTxError) - .inspect_err(|_| { - self.logger - .error("Failed to get latest block header", &[()]) - })?; - - // 2*baseFee + gas_tip_cap makes sure that the tx remains includeable for 6 consecutive 100% full blocks. - // see https://www.blocknative.com/blog/eip-1559-fees - let base_fee = header.base_fee_per_gas.ok_or(TxManagerError::SendTxError)?; - let gas_fee_cap = 2 * base_fee + gas_tip_cap; - - let mut gas_limit = tx.gas_limit(); - let tx_input = tx.input().to_vec(); - // we only estimate if gas_limit is not already set - if gas_limit == 0 { - let from = self.get_address()?; - let to = match tx.to() { - TxKind::Call(c) => c, - TxKind::Create => return Err(TxManagerError::SendTxError), - }; - let mut tx_request = TransactionRequest::default() - .to(to) - .from(from) - .value(tx.value()) - .input(TransactionInput::new(tx_input.clone().into())); - tx_request.set_max_priority_fee_per_gas(gas_tip_cap); - tx_request.set_max_fee_per_gas(gas_fee_cap); - - gas_limit = self - .provider - .estimate_gas(&tx_request) - .await - .map_err(|_| TxManagerError::SendTxError)?; - } - let gas_price_multiplied = - tx.gas_price().unwrap_or_default() as f64 * self.gas_limit_multiplier; - let gas_price = gas_price_multiplied as u128; - - let to = match tx.to() { - TxKind::Create => return Err(TxManagerError::SendTxError), - TxKind::Call(adress) => adress, - }; - - let new_tx = TransactionRequest::default() - .with_to(to) - .with_value(tx.value()) - .with_gas_limit(gas_limit) - .with_nonce(tx.nonce()) - .with_input(tx_input) - .with_chain_id(tx.chain_id().unwrap_or(1)) - .with_max_priority_fee_per_gas(gas_tip_cap) - .with_max_fee_per_gas(gas_fee_cap) - .with_gas_price(gas_price); - - Ok(new_tx) - } - - async fn estimate_gas_and_nonce_2( + async fn estimate_gas_and_nonce( &self, tx: &TransactionRequest, ) -> Result { From 6eb0cc1f1f9119202d580329ee63fb1d7650d721 Mon Sep 17 00:00:00 2001 From: juanbono Date: Fri, 9 Aug 2024 07:47:35 -0300 Subject: [PATCH 80/82] cargo clippy --- crates/chainio/txmanager/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index bf702e2a..69e8b0b4 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -9,7 +9,6 @@ license-file.workspace = true [dependencies] alloy-eips.workspace = true -alloy-consensus.workspace = true alloy-network.workspace = true alloy-primitives.workspace = true alloy-provider.workspace = true @@ -23,6 +22,7 @@ reqwest.workspace = true thiserror.workspace = true [dev-dependencies] +alloy-consensus.workspace = true alloy-node-bindings.workspace = true once_cell.workspace = true tokio.workspace = true From da6003f96edf94a130e350aa1764e49d0cdfec2e Mon Sep 17 00:00:00 2001 From: juanbono Date: Tue, 13 Aug 2024 12:54:46 -0300 Subject: [PATCH 81/82] address comments on docs --- crates/chainio/txmanager/src/simple_tx_manager.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 9ae72027..5274af36 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -98,10 +98,10 @@ impl<'log> SimpleTxManager<'log> { .map_err(|_| TxManagerError::SignerError) } - /// Send is used to send a transaction to the Ethereum node. It takes an unsigned/signed transaction - /// and then sends it to the Ethereum node. + /// Send is used to send a transaction to the Ethereum node. It takes an unsigned/signed transaction, + /// sends it to the Ethereum node and waits for the receipt. /// If you pass in a signed transaction it will ignore the signature - /// and resign the transaction after adding the nonce and gas limit. + /// and re-sign the transaction after adding the nonce and gas limit. /// /// # Arguments /// From 44bf5af0fdd88159facff15eb885a096093c115c Mon Sep 17 00:00:00 2001 From: juanbono Date: Tue, 13 Aug 2024 16:05:49 -0300 Subject: [PATCH 82/82] use correct function to get test logger --- .../txmanager/src/simple_tx_manager.rs | 19 +++++-------------- crates/logging/Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index 5274af36..fc224d24 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -98,7 +98,7 @@ impl<'log> SimpleTxManager<'log> { .map_err(|_| TxManagerError::SignerError) } - /// Send is used to send a transaction to the Ethereum node. It takes an unsigned/signed transaction, + /// Send is used to send a transaction to the Ethereum node. It takes an unsigned/signed transaction, /// sends it to the Ethereum node and waits for the receipt. /// If you pass in a signed transaction it will ignore the signature /// and re-sign the transaction after adding the nonce and gas limit. @@ -273,26 +273,21 @@ mod tests { use alloy_node_bindings::Anvil; use alloy_primitives::{bytes, TxKind::Call, U256}; use alloy_rpc_types_eth::TransactionRequest; - use eigen_logging::{log_level::LogLevel, logger::Logger, tracing_logger::TracingLogger}; - use once_cell::sync::OnceCell; + use eigen_logging::get_test_logger; use tokio; - static TEST_LOGGER: OnceCell = OnceCell::new(); const PRIVATE_KEY: &str = "dcf2cbdd171a21c480aa7f53d77f31bb102282b3ff099c78e3118b37348c72f7"; #[tokio::test] async fn test_send_transaction_from_legacy() { - TEST_LOGGER.get_or_init(|| { - TracingLogger::new_text_logger(false, String::from(""), LogLevel::Debug, false) - }); - // Spin up a local Anvil node. // Ensure `anvil` is available in $PATH. let anvil = Anvil::new().try_spawn().unwrap(); let rpc_url: String = anvil.endpoint().parse().unwrap(); // Create a provider. - let logger = TEST_LOGGER.get().unwrap(); + let logger = get_test_logger(); + let simple_tx_manager = SimpleTxManager::new(logger, 1.0, PRIVATE_KEY, rpc_url.as_str()).unwrap(); @@ -322,17 +317,13 @@ mod tests { #[tokio::test] async fn test_send_transaction_from_eip1559() { - TEST_LOGGER.get_or_init(|| { - TracingLogger::new_text_logger(false, String::from(""), LogLevel::Debug, false) - }); - // Spin up a local Anvil node. // Ensure `anvil` is available in $PATH. let anvil = Anvil::new().try_spawn().unwrap(); let rpc_url: String = anvil.endpoint().parse().unwrap(); // Create a provider. - let logger = TEST_LOGGER.get().unwrap(); + let logger = get_test_logger(); let simple_tx_manager = SimpleTxManager::new(logger, 1.0, PRIVATE_KEY, rpc_url.as_str()).unwrap(); diff --git a/crates/logging/Cargo.toml b/crates/logging/Cargo.toml index 2a59c302..7902b14e 100644 --- a/crates/logging/Cargo.toml +++ b/crates/logging/Cargo.toml @@ -9,4 +9,4 @@ repository.workspace = true ctor = "0.2.8" once_cell.workspace = true tracing-subscriber.workspace = true -tracing.workspace = true \ No newline at end of file +tracing.workspace = true