From 32871f1473e26f4afc2a58e353d4fec24f43e2fc Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Tue, 23 Jan 2024 11:34:23 +0100 Subject: [PATCH 01/41] Fix comment --- auction-server/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auction-server/src/config.rs b/auction-server/src/config.rs index 4c79aff0..aa966c9e 100644 --- a/auction-server/src/config.rs +++ b/auction-server/src/config.rs @@ -25,7 +25,7 @@ mod server; #[command(version = crate_version!())] #[allow(clippy::large_enum_variant)] pub enum Options { - /// Run the benchmarks streaming service. + /// Run the auction server service. Run(RunOptions), } From 95111ffb883fa8bb069f98b45bd73240b7a76d48 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Tue, 23 Jan 2024 11:35:36 +0100 Subject: [PATCH 02/41] Initialize project --- .gitignore | 2 + auction-server/.gitignore | 1 - vault-simulator/Cargo.lock | 4308 ++++++++++++++++++++++++++++++ vault-simulator/Cargo.toml | 28 + vault-simulator/src/config.rs | 43 + vault-simulator/src/main.rs | 39 + vault-simulator/src/simulator.rs | 0 7 files changed, 4420 insertions(+), 1 deletion(-) delete mode 100644 auction-server/.gitignore create mode 100644 vault-simulator/Cargo.lock create mode 100644 vault-simulator/Cargo.toml create mode 100644 vault-simulator/src/config.rs create mode 100644 vault-simulator/src/main.rs create mode 100644 vault-simulator/src/simulator.rs diff --git a/.gitignore b/.gitignore index 27fe92f1..cb1186e1 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ api_keys.py # env files *.env per_multicall/latestEnvironment.json + +**/target/ diff --git a/auction-server/.gitignore b/auction-server/.gitignore deleted file mode 100644 index eb5a316c..00000000 --- a/auction-server/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/vault-simulator/Cargo.lock b/vault-simulator/Cargo.lock new file mode 100644 index 00000000..04acf608 --- /dev/null +++ b/vault-simulator/Cargo.lock @@ -0,0 +1,4308 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version", +] + +[[package]] +name = "auto_impl" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core 0.3.4", + "base64 0.21.7", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http 0.2.11", + "http-body 0.4.6", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-auth" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8169113a185f54f68614fcfc3581df585d30bf8542bcb99496990e1025e4120a" +dependencies = [ + "async-trait", + "axum-core 0.4.3", + "base64 0.21.7", + "http 1.0.0", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 0.2.11", + "http-body 0.4.6", + "mime", + "rustversion", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "axum-streams" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07716a7fdcb5ec98c92d411b4ee8d55c056d51b585770e06ab83219307befc01" +dependencies = [ + "axum", + "bytes", + "cargo-husky", + "futures", + "futures-util", + "http 0.2.11", + "mime", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tokio-util", +] + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "sha2", + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +dependencies = [ + "serde", +] + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-husky" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b02b629252fe8ef6460461409564e2c21d0c8e77e0944f3d189ff06c4e932ad" + +[[package]] +name = "cargo-platform" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41daef31d7a747c5c847246f36de49ced6f7403b4cdabc807a97b5cc184cda7a" +dependencies = [ + "num-traits", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "coins-bip32" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58", + "coins-core", + "digest", + "hmac", + "k256", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec", + "coins-bip32", + "hmac", + "once_cell", + "pbkdf2 0.12.2", + "rand", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +dependencies = [ + "base64 0.21.7", + "bech32", + "bs58", + "digest", + "generic-array", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2", + "sha3", + "thiserror", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "const-hex" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "data-encoding" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys 0.3.7", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys 0.4.1", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe81b5c06ecfdbc71dd845216f225f53b62a10cb8a16c946836a3467f701d05b" +dependencies = [ + "base64 0.21.7", + "bytes", + "hex", + "k256", + "log", + "rand", + "rlp", + "serde", + "sha3", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest", + "hex", + "hmac", + "pbkdf2 0.11.0", + "rand", + "scrypt", + "serde", + "serde_json", + "sha2", + "sha3", + "thiserror", + "uuid 0.8.2", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5344eea9b20effb5efeaad29418215c4d27017639fd1f908260f59cbbd226e" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", + "ethers-solc", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bf35eb7d2e2092ad41f584951e08ec7c077b142dba29c4f1b8f52d2efddc49c" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0111ead599d17a7bff6985fd5756f39ca7033edc79a31b23026a8d5d64fa95cd" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbdfb952aafd385b31d316ed80d7b76215ce09743c172966d840e96924427e0c" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "ethers-etherscan", + "eyre", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "reqwest", + "serde", + "serde_json", + "syn 2.0.48", + "toml", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7465c814a2ecd0de0442160da13584205d1cdc08f4717a6511cad455bd5d7dc4" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.48", +] + +[[package]] +name = "ethers-core" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918b1a9ba585ea61022647def2f27c29ba19f6d2a4a4c8f68a9ae97fd5769737" +dependencies = [ + "arrayvec", + "bytes", + "cargo_metadata", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array", + "k256", + "num_enum", + "once_cell", + "open-fastrlp", + "rand", + "rlp", + "serde", + "serde_json", + "strum", + "syn 2.0.48", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-etherscan" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "facabf8551b4d1a3c08cb935e7fca187804b6c2525cc0dafb8e5a6dd453a24de" +dependencies = [ + "chrono", + "ethers-core", + "reqwest", + "semver", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681ece6eb1d10f7cf4f873059a77c04ff1de4f35c63dd7bccde8f438374fcb93" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25d6c0c9455d93d4990c06e049abf9b30daf148cf461ee939c11d88907c60816" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.7", + "bytes", + "const-hex", + "enr", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "http 0.2.11", + "instant", + "jsonwebtoken", + "once_cell", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-tungstenite", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb1b714e227bbd2d8c53528adb580b203009728b17d0d0e4119353aa9bc5532" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "const-hex", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "rand", + "sha2", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-solc" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2e46e3ec8ef0c986145901fa9864205dc4dcee701f9846be2d56112d34bdea" +dependencies = [ + "cfg-if", + "const-hex", + "dirs 5.0.1", + "dunce", + "ethers-core", + "glob", + "home", + "md-5", + "num_cpus", + "once_cell", + "path-slash", + "rayon", + "regex", + "semver", + "serde", + "serde_json", + "solang-parser", + "svm-rs", + "thiserror", + "tiny-keccak", + "tokio", + "tracing", + "walkdir", + "yansi", +] + +[[package]] +name = "eyre" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.11", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.11", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.0.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 0.2.11", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.11", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", + "serde", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is-terminal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +dependencies = [ + "base64 0.21.7", + "pem", + "ring 0.16.20", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools 0.10.5", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.7.5", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "prettyplease" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +dependencies = [ + "proc-macro2", + "syn 2.0.48", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bitflags 2.4.2", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.2", + "unarray", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.4", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http 0.2.11", + "http-body 0.4.6", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rust-embed" +version = "6.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a36224c3276f8c4ebc8c20f158eca7ca4359c8db89991c4925132aaaf6702661" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "6.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b94b81e5b2c284684141a2fb9e2a31be90638caf040bf9afbc5a0416afe1ac" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "shellexpand", + "syn 2.0.48", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "7.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d38ff6bf570dc3bb7100fce9f7b60c33fa71d80e88da3f2580df4ff2bdded74" +dependencies = [ + "sha2", + "walkdir", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring 0.17.7", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-info" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2 0.11.0", + "salsa20", + "sha2", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +dependencies = [ + "serde", +] + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "serde_json" +version = "1.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1bf28c79a99f70ee1f1d83d10c875d2e70618417fda01ad1785e027579d9d38" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shellexpand" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4" +dependencies = [ + "dirs 4.0.0", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "solang-parser" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" +dependencies = [ + "itertools 0.11.0", + "lalrpop", + "lalrpop-util", + "phf", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.48", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "svm-rs" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20689c7d03b6461b502d0b95d6c24874c7d24dea2688af80486a130a06af3b07" +dependencies = [ + "dirs 5.0.1", + "fs2", + "hex", + "once_cell", + "reqwest", + "semver", + "serde", + "serde_json", + "sha2", + "thiserror", + "url", + "zip", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +dependencies = [ + "deranged", + "itoa", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +dependencies = [ + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.21.0", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +dependencies = [ + "bitflags 2.4.2", + "bytes", + "futures-core", + "futures-util", + "http 0.2.11", + "http-body 0.4.6", + "http-range-header", + "pin-project-lite", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 0.2.11", + "httparse", + "log", + "rand", + "rustls", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "utoipa" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82b1bc5417102a73e8464c686eef947bdfb99fcdfc0a4f228e81afa9526470a" +dependencies = [ + "indexmap", + "serde", + "serde_json", + "utoipa-gen", +] + +[[package]] +name = "utoipa-gen" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d96dcd6fc96f3df9b3280ef480770af1b7c5d14bc55192baa9b067976d920c" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "regex", + "syn 2.0.48", +] + +[[package]] +name = "utoipa-swagger-ui" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84614caa239fb25b2bb373a52859ffd94605ceb256eeb1d63436325cf81e3653" +dependencies = [ + "axum", + "mime_guess", + "regex", + "rust-embed", + "serde", + "serde_json", + "utoipa", + "zip", +] + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "uuid" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vault-simulator" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-stream", + "axum", + "axum-auth", + "axum-macros", + "axum-streams", + "clap", + "ethers", + "futures", + "serde", + "serde_json", + "serde_yaml", + "tokio", + "tokio-stream", + "tower-http", + "tracing", + "tracing-subscriber", + "utoipa", + "utoipa-swagger-ui", + "uuid 1.7.0", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" + +[[package]] +name = "web-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version", + "send_wrapper 0.6.0", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2 0.11.0", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/vault-simulator/Cargo.toml b/vault-simulator/Cargo.toml new file mode 100644 index 00000000..56a3a1d8 --- /dev/null +++ b/vault-simulator/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "vault-simulator" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tokio = { version = "1.28", features = ["macros", "sync", "rt-multi-thread", "signal"] } +tokio-stream = "0.1.14" +tower-http = { version = "0.4.0", features = ["cors"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +futures = { version = "0.3", default-features = false } +uuid = { version = "1.1.2", features = ["serde", "v4"] } +axum = { version = "0.6.20", features = ["ws", "tracing"] } +axum-streams = { version = "0.10.0", features = ["json", "text"] } +clap = { version = "4.4.4", features = ["derive", "env", "cargo"] } +tracing = { version = "0.1.40", features = ["log"] } +anyhow = "1.0.75" +tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] } +async-stream = "0.3.5" +utoipa = { version = "3.4.0", features = ["axum_extras"] } +utoipa-swagger-ui = { version = "3.1.4", features = ["axum"] } +serde_yaml = "0.9.25" +ethers = "2.0.10" +axum-macros = "0.4.0" +axum-auth = "0.7.0" diff --git a/vault-simulator/src/config.rs b/vault-simulator/src/config.rs new file mode 100644 index 00000000..cf386f4b --- /dev/null +++ b/vault-simulator/src/config.rs @@ -0,0 +1,43 @@ +use { + anyhow::Result, + clap::{ + crate_authors, + crate_description, + crate_name, + crate_version, + Args, + Parser, + }, + ethers::abi::Address, + std::{ + collections::HashMap, + fs, + net::SocketAddr, + }, +}; + +// `Options` is a structup definition to provide clean command-line args for Hermes. +#[derive(Parser, Debug)] +#[command(name = crate_name!())] +#[command(author = crate_authors!())] +#[command(about = crate_description!())] +#[command(version = crate_version!())] +#[allow(clippy::large_enum_variant)] +pub enum Options { + /// Run the simulator. + Run(RunOptions), +} + +#[derive(Args, Clone, Debug)] +pub struct RunOptions { + + /// Address and port the server will bind to. + #[arg(long = "rpc-addr")] + #[arg(env = "RPC_ADDR")] + pub listen_addr: SocketAddr, + + /// A 20-byte (40 char) hex encoded Ethereum private key which is used for submitting transactions. + #[arg(long = "private-key")] + #[arg(env = "PRIVATE_KEY")] + pub private_key: String, +} diff --git a/vault-simulator/src/main.rs b/vault-simulator/src/main.rs new file mode 100644 index 00000000..d56ab74d --- /dev/null +++ b/vault-simulator/src/main.rs @@ -0,0 +1,39 @@ +use { + anyhow::Result, + clap::Parser, + std::io::IsTerminal, + tracing_subscriber::filter::LevelFilter, +}; + +mod config; + +#[tokio::main] +async fn main() -> Result<()> { + // Initialize a Tracing Subscriber + let fmt_builder = tracing_subscriber::fmt() + .with_file(false) + .with_line_number(true) + .with_thread_ids(true) + .with_env_filter( + tracing_subscriber::EnvFilter::builder() + .with_default_directive(LevelFilter::INFO.into()) + .from_env_lossy(), + ) + .with_ansi(std::io::stderr().is_terminal()); + + // Use the compact formatter if we're in a terminal, otherwise use the JSON formatter. + if std::io::stderr().is_terminal() { + tracing::subscriber::set_global_default(fmt_builder.compact().finish())?; + } else { + tracing::subscriber::set_global_default(fmt_builder.json().finish())?; + } + + // Parse the command line arguments with StructOpt, will exit automatically on `--help` or + // with invalid arguments. + match config::Options::parse() { + config::Options::Run(opts) => { + + }, + }; + Ok(()) +} diff --git a/vault-simulator/src/simulator.rs b/vault-simulator/src/simulator.rs new file mode 100644 index 00000000..e69de29b From dbee4dc139ae1439b0cf8ae98a3fa94a0a799824 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 28 Jan 2024 11:08:05 +0100 Subject: [PATCH 03/41] First version of the simulator --- vault-simulator/Cargo.lock | 145 ++++++++++++++++++ vault-simulator/Cargo.toml | 4 + vault-simulator/src/config.rs | 52 +++++-- vault-simulator/src/main.rs | 6 +- vault-simulator/src/simulator.rs | 244 +++++++++++++++++++++++++++++++ 5 files changed, 436 insertions(+), 15 deletions(-) diff --git a/vault-simulator/Cargo.lock b/vault-simulator/Cargo.lock index 04acf608..ec3765a4 100644 --- a/vault-simulator/Cargo.lock +++ b/vault-simulator/Cargo.lock @@ -1330,6 +1330,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1712,6 +1727,19 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "idna" version = "0.5.0" @@ -2037,6 +2065,24 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "new_debug_unreachable" version = "1.0.4" @@ -2155,6 +2201,50 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "openssl" +version = "0.10.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" +dependencies = [ + "bitflags 2.4.2", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -2668,10 +2758,12 @@ dependencies = [ "http-body 0.4.6", "hyper", "hyper-rustls", + "hyper-tls", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -2682,6 +2774,7 @@ dependencies = [ "serde_urlencoded", "system-configuration", "tokio", + "tokio-native-tls", "tokio-rustls", "tower-service", "url", @@ -2916,6 +3009,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2958,6 +3060,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.21" @@ -3466,6 +3591,16 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -3907,9 +4042,12 @@ dependencies = [ "axum-auth", "axum-macros", "axum-streams", + "base64 0.21.7", "clap", "ethers", "futures", + "rand", + "reqwest", "serde", "serde_json", "serde_yaml", @@ -3918,11 +4056,18 @@ dependencies = [ "tower-http", "tracing", "tracing-subscriber", + "url", "utoipa", "utoipa-swagger-ui", "uuid 1.7.0", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" diff --git a/vault-simulator/Cargo.toml b/vault-simulator/Cargo.toml index 56a3a1d8..62232aa2 100644 --- a/vault-simulator/Cargo.toml +++ b/vault-simulator/Cargo.toml @@ -26,3 +26,7 @@ serde_yaml = "0.9.25" ethers = "2.0.10" axum-macros = "0.4.0" axum-auth = "0.7.0" +url = "2.5.0" +rand = "0.8.5" +reqwest = "0.11.23" +base64 = "0.21.7" diff --git a/vault-simulator/src/config.rs b/vault-simulator/src/config.rs index cf386f4b..65fa6e3e 100644 --- a/vault-simulator/src/config.rs +++ b/vault-simulator/src/config.rs @@ -1,19 +1,9 @@ use { anyhow::Result, - clap::{ - crate_authors, - crate_description, - crate_name, - crate_version, - Args, - Parser, - }, + clap::{crate_authors, crate_description, crate_name, crate_version, Arg, ArgAction, Args, Parser}, ethers::abi::Address, - std::{ - collections::HashMap, - fs, - net::SocketAddr, - }, + std::{collections::HashMap, fs, net::SocketAddr}, + url::Url, }; // `Options` is a structup definition to provide clean command-line args for Hermes. @@ -26,18 +16,52 @@ use { pub enum Options { /// Run the simulator. Run(RunOptions), + + /// Deploy the token vault contract. + Deploy(DeployOptions), } #[derive(Args, Clone, Debug)] pub struct RunOptions { + /// Address and port the server will bind to. + #[arg(long = "rpc-addr")] + #[arg(env = "RPC_ADDR")] + pub rpc_addr: Url, + + /// A 20-byte (40 char) hex encoded Ethereum private key which is used for submitting transactions. + #[arg(long = "private-key")] + #[arg(env = "PRIVATE_KEY")] + pub private_key: String, + /// The address of the contract to interact with. + #[arg(long = "contract")] + pub contract: Address, + + #[arg(long = "token")] + pub tokens: Vec
, + + #[arg(long = "weth")] + pub weth: Address, +} + +#[derive(Args, Clone, Debug)] +pub struct DeployOptions { /// Address and port the server will bind to. #[arg(long = "rpc-addr")] #[arg(env = "RPC_ADDR")] - pub listen_addr: SocketAddr, + pub rpc_addr: Url, /// A 20-byte (40 char) hex encoded Ethereum private key which is used for submitting transactions. #[arg(long = "private-key")] #[arg(env = "PRIVATE_KEY")] pub private_key: String, + + + /// The per contract address + #[arg(long = "per-contract")] + pub per_contract: Address, + + /// The oracle contract address + #[arg(long = "oracle-contract")] + pub oracle_contract: Address, } diff --git a/vault-simulator/src/main.rs b/vault-simulator/src/main.rs index d56ab74d..d530f625 100644 --- a/vault-simulator/src/main.rs +++ b/vault-simulator/src/main.rs @@ -6,6 +6,7 @@ use { }; mod config; +mod simulator; #[tokio::main] async fn main() -> Result<()> { @@ -32,7 +33,10 @@ async fn main() -> Result<()> { // with invalid arguments. match config::Options::parse() { config::Options::Run(opts) => { - + simulator::run_simulator(opts).await?; + }, + config::Options::Deploy(opts) => { + simulator::deploy_contract(opts).await?; }, }; Ok(()) diff --git a/vault-simulator/src/simulator.rs b/vault-simulator/src/simulator.rs index e69de29b..6f3a61c1 100644 --- a/vault-simulator/src/simulator.rs +++ b/vault-simulator/src/simulator.rs @@ -0,0 +1,244 @@ +use ethers::contract::ContractError; +use ethers::core::utils::hex::FromHex; + +use base64::prelude::*; +use ethers::abi::Address; +use ethers::{ + contract::abigen, + middleware::SignerMiddleware, + providers::{Http, Middleware, Provider}, + signers::{LocalWallet, Signer}, + types::{Bytes, U256}, +}; +use rand::{random, seq::SliceRandom}; +use serde_json::Value; +use std::sync::Arc; +use url::Url; + +use crate::config::{DeployOptions, RunOptions}; +use anyhow::{anyhow, Context, Result}; + +abigen!( + TokenVault, + "../per_multicall/out/TokenVault.sol/TokenVault.json" +); + +abigen!(ERC20, "../per_multicall/out/MyToken.sol/MyToken.json"); +abigen!(IPyth, "../per_multicall/out/IPyth.sol/IPyth.json"); + +pub type SignableTokenVaultContract = TokenVault, LocalWallet>>; + +#[derive(Clone)] +struct PythUpdate { + price: U256, + vaa: Bytes, +} + +#[derive(Clone)] +struct TokenInfo { + symbol: String, + price_id: String, + address: Address, + contract: ERC20, LocalWallet>>, +} + +async fn get_token_info( + token: Address, + client: Arc, LocalWallet>>, +) -> Result { + let contract = ERC20::new(token, client.clone()); + let symbol = contract.symbol().await?; + let price_id = contract.name().await?; + Ok(TokenInfo { + symbol, + price_id, + address: token, + contract, + }) +} + +fn parse_update(update: Value) -> Result { + let price_component = update["price"].clone(); + let price = U256::from_dec_str(price_component["price"].as_str().unwrap()).unwrap(); + let expo = price_component["expo"].as_i64().unwrap() + 18; // use 18 as max exponent + tracing::info!("Price: {}, Exponent: {}", price, expo); + let multiple = U256::exp10(expo.try_into().map_err(|_| anyhow!("Invalid exponent"))?); + + Ok(PythUpdate { + price: price * multiple, + vaa: Bytes::from( + BASE64_STANDARD + .decode(update["vaa"].as_str().unwrap()) + .unwrap(), + ), + }) +} + +async fn get_latest_updates(feed_ids: Vec) -> Result> { + let url = Url::parse_with_params( + "https://hermes.pyth.network/api/latest_price_feeds?verbose=true&binary=true", + feed_ids + .iter() + .map(|id| ("ids[]", id.to_string())) + .collect::>() + .as_slice(), + )?; + let response = reqwest::get(url).await?; + let updates = response.json::().await?; + (updates) + .as_array() + .context(format!("Invalid response: {:?}", updates))? + .into_iter() + .map(|update| parse_update(update.clone())) + .collect() +} + +pub async fn run_simulator(options: RunOptions) -> Result<()> { + let wallet = options + .private_key + .parse::() + .map_err(|e| anyhow!("Can not parse private key: {}", e))?; + tracing::info!("Using wallet address: {}", wallet.address().to_string()); + let provider = Provider::::try_from(options.rpc_addr.as_str()).map_err(|err| { + anyhow!( + "Failed to connect to {rpc_addr}: {:?}", + err, + rpc_addr = options.rpc_addr + ) + })?; + let chain_id = provider.get_chainid().await?; + tracing::info!("Connected to chain: {}", chain_id); + + // check the balance of the wallet + let wallet_address = wallet.address(); + let balance = provider.get_balance(wallet_address, None).await?; + tracing::info!("Wallet balance: {}", balance); + + let client = Arc::new(SignerMiddleware::new( + provider, + wallet.with_chain_id(chain_id.as_u64()), + )); + + let sample: [&Address; 2] = options + .tokens + .choose_multiple(&mut rand::thread_rng(), 2) + .collect::>() + .try_into() + .map_err(|_| anyhow!("Unable to sample 2 tokens as colateral and debt"))?; + + let [collateral, debt] = sample; + let collateral_info = get_token_info(*collateral, client.clone()).await?; + let debt_info = get_token_info(*debt, client.clone()).await?; + + tracing::info!( + "Collateral Symbol: {} price id: {}", + collateral_info.symbol, + collateral_info.price_id + ); + tracing::info!( + "Debt Symbol: {} price id: {}", + debt_info.symbol, + debt_info.price_id + ); + + // get the latest pyth updates + let updates = get_latest_updates(vec![ + collateral_info.price_id.clone(), + debt_info.price_id.clone(), + ]) + .await?; + let collateral_update = updates[0].clone(); + let debt_update = updates[1].clone(); + + // usd value random between 100 and 1000 dollars + let precision = U256::exp10(18); + let collateral_value_usd: U256 = precision * U256::from(random::() % 900 + 100); + tracing::info!("Collateral value usd: {}", collateral_value_usd); + + tracing::info!("Collateral price: {}", collateral_update.price); + tracing::info!("Debt price: {}", collateral_update.price); + + let amount_collateral: U256 = + collateral_value_usd * precision * 111 / 100 / collateral_update.price; // 10% more safety margin + let amount_debt = collateral_value_usd * precision / debt_update.price; + + let min_health_ratio = U256::exp10(18) * 110 / 100; + let min_permission_less_health_ratio = U256::exp10(18) * 105 / 100; + + let token_id_collateral: [u8; 32] = <[u8; 32]>::from_hex(collateral_info.price_id).unwrap(); + let token_id_debt: [u8; 32] = <[u8; 32]>::from_hex(debt_info.price_id).unwrap(); + let update_data = vec![collateral_update.vaa, debt_update.vaa]; + // let update_data = vec![]; + + collateral_info + .contract + .mint(wallet_address, amount_collateral) + .send() + .await?; + collateral_info + .contract + .approve(options.contract, amount_collateral) + .send() + .await?; + + tracing::info!("Calling create_vault"); + tracing::info!("Amount collateral: {}", amount_collateral); + tracing::info!("Amount debt: {}", amount_debt); + + let contract = SignableTokenVaultContract::new(options.contract, client.clone()); + let tx = contract + .create_vault( + collateral_info.address, + debt_info.address, + amount_collateral, + amount_debt, + min_health_ratio, + min_permission_less_health_ratio, + token_id_collateral, + token_id_debt, + update_data.clone(), + ) + .value(update_data.len()); + let result: Result<_, ContractError<_>> = tx.send().await; + match result { + Ok(_) => { + tracing::info!("Vault created"); + } + Err(e) => { + let decoded = e.decode_contract_revert::(); + tracing::info!("Error creating vault: {:?}", decoded); + } + } + + Ok(()) +} + +pub async fn deploy_contract(options: DeployOptions) -> Result<()> { + let wallet = options + .private_key + .parse::() + .map_err(|e| anyhow!("Can not parse private key: {}", e))?; + tracing::info!("Using wallet address: {}", wallet.address().to_string()); + let provider = Provider::::try_from(options.rpc_addr.as_str()).map_err(|err| { + anyhow!( + "Failed to connect to {rpc_addr}: {:?}", + err, + rpc_addr = options.rpc_addr + ) + })?; + let chain_id = provider.get_chainid().await?; + tracing::info!("Connected to chain id: {}", chain_id); + + let client = Arc::new(SignerMiddleware::new( + provider, + wallet.with_chain_id(chain_id.as_u64()), + )); + let contract = SignableTokenVaultContract::deploy( + client, + (options.per_contract, options.oracle_contract), + )? + .send() + .await?; + tracing::info!("{}", contract.address().to_string()); + Ok(()) +} From bbce0ee0ec6c8c0ac0414eedd9fc8b425ff15c53 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 28 Jan 2024 11:09:39 +0100 Subject: [PATCH 04/41] Add to pre-commit formatting --- .pre-commit-config.yaml | 9 +++++ vault-simulator/src/config.rs | 18 +++++++-- vault-simulator/src/main.rs | 4 +- vault-simulator/src/simulator.rs | 66 +++++++++++++++++++++----------- 4 files changed, 70 insertions(+), 27 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 709f4b34..946beb7d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,6 +24,15 @@ repos: entry: cargo +nightly-2023-07-23 fmt --manifest-path ./auction-server/Cargo.toml --all -- --config-path rustfmt.toml pass_filenames: false files: auction-server + - repo: local + hooks: + # Hooks for vault-simulator + - id: cargo-fmt-vault-simulator + name: Cargo format for vault simulator + language: "rust" + entry: cargo +nightly-2023-07-23 fmt --manifest-path ./vault-simulator/Cargo.toml --all -- --config-path rustfmt.toml + pass_filenames: false + files: vault-simulator # for python files - repo: https://github.com/hhatto/autopep8 diff --git a/vault-simulator/src/config.rs b/vault-simulator/src/config.rs index 65fa6e3e..e266fa1d 100644 --- a/vault-simulator/src/config.rs +++ b/vault-simulator/src/config.rs @@ -1,8 +1,21 @@ use { anyhow::Result, - clap::{crate_authors, crate_description, crate_name, crate_version, Arg, ArgAction, Args, Parser}, + clap::{ + crate_authors, + crate_description, + crate_name, + crate_version, + Arg, + ArgAction, + Args, + Parser, + }, ethers::abi::Address, - std::{collections::HashMap, fs, net::SocketAddr}, + std::{ + collections::HashMap, + fs, + net::SocketAddr, + }, url::Url, }; @@ -56,7 +69,6 @@ pub struct DeployOptions { #[arg(env = "PRIVATE_KEY")] pub private_key: String, - /// The per contract address #[arg(long = "per-contract")] pub per_contract: Address, diff --git a/vault-simulator/src/main.rs b/vault-simulator/src/main.rs index d530f625..0282d498 100644 --- a/vault-simulator/src/main.rs +++ b/vault-simulator/src/main.rs @@ -34,10 +34,10 @@ async fn main() -> Result<()> { match config::Options::parse() { config::Options::Run(opts) => { simulator::run_simulator(opts).await?; - }, + } config::Options::Deploy(opts) => { simulator::deploy_contract(opts).await?; - }, + } }; Ok(()) } diff --git a/vault-simulator/src/simulator.rs b/vault-simulator/src/simulator.rs index 6f3a61c1..1bc4bb45 100644 --- a/vault-simulator/src/simulator.rs +++ b/vault-simulator/src/simulator.rs @@ -1,22 +1,44 @@ -use ethers::contract::ContractError; -use ethers::core::utils::hex::FromHex; - -use base64::prelude::*; -use ethers::abi::Address; -use ethers::{ - contract::abigen, - middleware::SignerMiddleware, - providers::{Http, Middleware, Provider}, - signers::{LocalWallet, Signer}, - types::{Bytes, U256}, +use { + crate::config::{ + DeployOptions, + RunOptions, + }, + anyhow::{ + anyhow, + Context, + Result, + }, + base64::prelude::*, + ethers::{ + abi::Address, + contract::{ + abigen, + ContractError, + }, + core::utils::hex::FromHex, + middleware::SignerMiddleware, + providers::{ + Http, + Middleware, + Provider, + }, + signers::{ + LocalWallet, + Signer, + }, + types::{ + Bytes, + U256, + }, + }, + rand::{ + random, + seq::SliceRandom, + }, + serde_json::Value, + std::sync::Arc, + url::Url, }; -use rand::{random, seq::SliceRandom}; -use serde_json::Value; -use std::sync::Arc; -use url::Url; - -use crate::config::{DeployOptions, RunOptions}; -use anyhow::{anyhow, Context, Result}; abigen!( TokenVault, @@ -31,14 +53,14 @@ pub type SignableTokenVaultContract = TokenVault #[derive(Clone)] struct PythUpdate { price: U256, - vaa: Bytes, + vaa: Bytes, } #[derive(Clone)] struct TokenInfo { - symbol: String, + symbol: String, price_id: String, - address: Address, + address: Address, contract: ERC20, LocalWallet>>, } @@ -66,7 +88,7 @@ fn parse_update(update: Value) -> Result { Ok(PythUpdate { price: price * multiple, - vaa: Bytes::from( + vaa: Bytes::from( BASE64_STANDARD .decode(update["vaa"].as_str().unwrap()) .unwrap(), From c6295bf277c00d2810ff8627c39206c41d91fd41 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 28 Jan 2024 11:14:58 +0100 Subject: [PATCH 05/41] Refactor setup script --- per_multicall/README.md | 2 +- per_multicall/script/Vault.s.sol | 23 ++++++----------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/per_multicall/README.md b/per_multicall/README.md index 64b20b8e..3296a09d 100644 --- a/per_multicall/README.md +++ b/per_multicall/README.md @@ -26,7 +26,7 @@ $ forge test -vvv --via-ir You can also run a local validator via `anvil --gas-limit 500000000000000000 --block-time 2`, changing the values for the gas limit and block time as desired. Note that if you omit the `--block-time` flag, the local network will create a new block for each transaction (similar to how Optimism created L2 blocks pre-Bedrock). Running `auction_offchain.py` will spit out the final call to `forge script` you should run to send the transaction to the localnet. -To run the script runs in `Vault.s.sol`, you should startup the local validator. Then, run the necessary setup commands: +To run the script runs in `Vault.s.sol`, you should startup the local validator and create a `.env` file with the `PRIVATE_KEY` env variable which is used for submitting the transactions. Then, run the necessary setup commands: 1. Set up contracts and save to an environment JSON. diff --git a/per_multicall/script/Vault.s.sol b/per_multicall/script/Vault.s.sol index b2d01b7f..795bb342 100644 --- a/per_multicall/script/Vault.s.sol +++ b/per_multicall/script/Vault.s.sol @@ -28,19 +28,14 @@ contract VaultScript is Script { string public latestEnvironmentPath = "latestEnvironment.json"; function getAnvil() public view returns (address, uint256) { - // TODO: these are mnemonic wallets. figure out how to transfer ETH from them outside of explicitly hardcoding them here. - return ( - address(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266), - 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 - ); + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + address deployerAddress = vm.addr(deployerPrivateKey); + return (deployerAddress, deployerPrivateKey); } function deployWeth() public returns (address) { - (, uint256 skanvil) = getAnvil(); - vm.startBroadcast(skanvil); WETH9 weth = new WETH9(); console.log("deployed weth contract at", address(weth)); - vm.stopBroadcast(); return address(weth); } @@ -50,9 +45,6 @@ contract VaultScript is Script { ); console.log("pk per operator", perOperatorAddress); console.log("sk per operator", perOperatorSk); - (, uint256 skanvil) = getAnvil(); - - vm.startBroadcast(skanvil); payable(perOperatorAddress).transfer(10 ether); PERMulticall multicall = new PERMulticall(perOperatorAddress, 0); console.log("deployed PER contract at", address(multicall)); @@ -60,7 +52,6 @@ contract VaultScript is Script { address(multicall), wethAddress ); - vm.stopBroadcast(); return (address(multicall), address(liquidationAdapter)); } @@ -71,19 +62,14 @@ contract VaultScript is Script { // make token vault deployer wallet (, uint256 tokenVaultDeployerSk) = makeAddrAndKey("tokenVaultDeployer"); console.log("sk token vault deployer", tokenVaultDeployerSk); - vm.startBroadcast(tokenVaultDeployerSk); TokenVault vault = new TokenVault(multicall, oracle); console.log("deployed vault contract at", address(vault)); - vm.stopBroadcast(); return address(vault); } function deployMockPyth() public returns (address) { - (, uint256 skanvil) = getAnvil(); - vm.startBroadcast(skanvil); MockPyth mockPyth = new MockPyth(1_000_000, 0); console.log("deployed mock pyth contract at", address(mockPyth)); - vm.stopBroadcast(); return address(mockPyth); } @@ -91,10 +77,13 @@ contract VaultScript is Script { public returns (address, address, address, address, address) { + (, uint256 skanvil) = getAnvil(); + vm.startBroadcast(skanvil); address weth = deployWeth(); (address per, address liquidationAdapter) = deployPER(weth); address mockPyth = deployMockPyth(); address vault = deployVault(per, mockPyth); + vm.stopBroadcast(); return (per, liquidationAdapter, mockPyth, vault, weth); } From aa5d4beddfd893d9fa627c1e47f4cbac3be4d84c Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 28 Jan 2024 11:20:05 +0100 Subject: [PATCH 06/41] Add setupTestnet script --- per_multicall/script/Vault.s.sol | 61 ++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/per_multicall/script/Vault.s.sol b/per_multicall/script/Vault.s.sol index 795bb342..a7c130a1 100644 --- a/per_multicall/script/Vault.s.sol +++ b/per_multicall/script/Vault.s.sol @@ -87,8 +87,66 @@ contract VaultScript is Script { return (per, liquidationAdapter, mockPyth, vault, weth); } + /** + @notice Sets up the testnet environment + deploys WETH, PER, LiquidationAdapter, TokenVault along with 5 ERC-20 tokens to use as collateral and debt tokens + The erc-20 tokens have their actual name as symbol and pyth price feed id as their name. A huge amount of these tokens are minted to the token vault + @param pyth The address of the already deployed pyth contract to use + */ + function setUpTestnet(address pyth) public { + (, uint256 skanvil) = getAnvil(); + vm.startBroadcast(skanvil); + address weth = deployWeth(); + (address per, address liquidationAdapter) = deployPER(weth); + address vault = deployVault(per, pyth); + vm.startBroadcast(skanvil); + address[] memory tokens = new address[](5); + uint256 lots_of_money = 10 ** 36; + tokens[0] = address( + new MyToken( + "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", + "BTC" + ) + ); + tokens[1] = address( + new MyToken( + "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a", + "USDC" + ) + ); + tokens[2] = address( + new MyToken( + "dcef50dd0a4cd2dcc17e45df1676dcb336a11a61c69df7a0299b0150c672d25c", + "DOGE" + ) + ); + tokens[3] = address( + new MyToken( + "ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d", + "SOL" + ) + ); + tokens[4] = address( + new MyToken( + "0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff", + "PYTH" + ) + ); + for (uint i = 0; i < 5; i++) { + MyToken(tokens[i]).mint(tokenVault, lots_of_money); + } + vm.stopBroadcast(); + string memory obj = ""; + vm.serializeAddress(obj, "tokens", tokens); + vm.serializeAddress(obj, "per", per); + vm.serializeAddress(obj, "liquidationAdapter", liquidationAdapter); + vm.serializeAddress(obj, "oracle", oracle); + vm.serializeAddress(obj, "tokenVault", tokenVault); + string memory finalJSON = vm.serializeAddress(obj, "weth", weth); + vm.writeJson(finalJSON, latestEnvironmentPath); + } + function setUpContracts() public { - console.log("balance of this contract", address(this).balance); SearcherVault searcherA; SearcherVault searcherB; @@ -274,7 +332,6 @@ contract VaultScript is Script { vm.serializeAddress(obj, "tokenVaultDeployer", addressesScript[4]); vm.serializeUint(obj, "tokenVaultDeployerSk", sksScript[4]); string memory finalJSON = vm.serializeUint(obj, "numVaults", 0); - vm.writeJson(finalJSON, latestEnvironmentPath); } From 41e5fff107e7bff7c40eab6a0722013c82266c46 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 28 Jan 2024 11:21:22 +0100 Subject: [PATCH 07/41] Small changes to TokenVault contract for easier integration with the actual pyth contract --- per_multicall/script/Vault.s.sol | 6 ++-- per_multicall/src/TokenVault.sol | 53 ++++++++++++++++++++++--------- per_multicall/test/PERVault.t.sol | 6 ++-- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/per_multicall/script/Vault.s.sol b/per_multicall/script/Vault.s.sol index a7c130a1..7b7b0b65 100644 --- a/per_multicall/script/Vault.s.sol +++ b/per_multicall/script/Vault.s.sol @@ -410,7 +410,8 @@ contract VaultScript is Script { 110 * (10 ** 16), 1 * (10 ** 16), idToken1Latest, - idToken2Latest + idToken2Latest, + new bytes[](0) ); vm.stopBroadcast(); } else { @@ -424,7 +425,8 @@ contract VaultScript is Script { 110 * (10 ** 16), 1 * (10 ** 16), idToken1Latest, - idToken2Latest + idToken2Latest, + new bytes[](0) ); vm.stopBroadcast(); } diff --git a/per_multicall/src/TokenVault.sol b/per_multicall/src/TokenVault.sol index aec4a49f..5651c01c 100644 --- a/per_multicall/src/TokenVault.sol +++ b/per_multicall/src/TokenVault.sol @@ -15,7 +15,7 @@ import "openzeppelin-contracts/contracts/utils/Strings.sol"; import {MyToken} from "./MyToken.sol"; import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol"; -import "@pythnetwork/pyth-sdk-solidity/MockPyth.sol"; +import "@pythnetwork/pyth-sdk-solidity/IPyth.sol"; contract TokenVault is PERFeeReceiver { using SafeERC20 for IERC20; @@ -39,17 +39,35 @@ contract TokenVault is PERFeeReceiver { _oracle = oracleAddress; } + function convertToUint( + PythStructs.Price memory price, + uint8 targetDecimals + ) private pure returns (uint256) { + if (price.price < 0 || price.expo > 0 || price.expo < -255) { + revert(); + } + + uint8 priceDecimals = uint8(uint32(-1 * price.expo)); + + if (targetDecimals >= priceDecimals) { + return + uint(uint64(price.price)) * + 10 ** uint32(targetDecimals - priceDecimals); + } else { + return + uint(uint64(price.price)) / + 10 ** uint32(priceDecimals - targetDecimals); + } + } + /** * @notice getPrice function - retrieves price of a given token from the oracle * * @param id: price feed ID of the token */ - function _getPrice( - bytes32 id - ) internal view returns (PythStructs.Price memory) { - MockPyth oracle = MockPyth(payable(_oracle)); - PythStructs.PriceFeed memory priceFeed = oracle.queryPriceFeed(id); - return priceFeed.price; + function _getPrice(bytes32 id) internal view returns (uint256) { + IPyth oracle = IPyth(payable(_oracle)); + return convertToUint(oracle.getPrice(id), 18); } function getOracle() public view returns (address) { @@ -74,15 +92,14 @@ contract TokenVault is PERFeeReceiver { function _getVaultHealth( Vault memory vault ) internal view returns (uint256) { - int64 priceCollateral = _getPrice(vault.tokenIDCollateral).price; - int64 priceDebt = _getPrice(vault.tokenIDDebt).price; + uint256 priceCollateral = _getPrice(vault.tokenIDCollateral); + uint256 priceDebt = _getPrice(vault.tokenIDDebt); require(priceCollateral >= 0, "collateral price is negative"); require(priceDebt >= 0, "debt price is negative"); - uint256 valueCollateral = uint256(uint64(priceCollateral)) * - vault.amountCollateral; - uint256 valueDebt = uint256(uint64(priceDebt)) * vault.amountDebt; + uint256 valueCollateral = priceCollateral * vault.amountCollateral; + uint256 valueDebt = priceDebt * vault.amountDebt; return (valueCollateral * 1_000_000_000_000_000_000) / valueDebt; } @@ -98,6 +115,7 @@ contract TokenVault is PERFeeReceiver { * @param minPermissionLessHealthRatio: minimum health ratio of the vault before permissionless liquidations are allowed. This should be less than minHealthRatio * @param tokenIDCollateral: price feed ID of the collateral token * @param tokenIDDebt: price feed ID of the debt token + * @param updateData: data to update price feeds with */ function createVault( address tokenCollateral, @@ -107,8 +125,10 @@ contract TokenVault is PERFeeReceiver { uint256 minHealthRatio, uint256 minPermissionLessHealthRatio, bytes32 tokenIDCollateral, - bytes32 tokenIDDebt - ) public returns (uint256) { + bytes32 tokenIDDebt, + bytes[] calldata updateData + ) public payable returns (uint256) { + _updatePriceFeeds(updateData); Vault memory vault = Vault( tokenCollateral, tokenDebt, @@ -224,7 +244,10 @@ contract TokenVault is PERFeeReceiver { * @param updateData: data to update price feeds with */ function _updatePriceFeeds(bytes[] calldata updateData) internal { - MockPyth oracle = MockPyth(payable(_oracle)); + if (updateData.length == 0) { + return; + } + IPyth oracle = IPyth(payable(_oracle)); oracle.updatePriceFeeds{value: msg.value}(updateData); } diff --git a/per_multicall/test/PERVault.t.sol b/per_multicall/test/PERVault.t.sol index b00500f7..1cfa654b 100644 --- a/per_multicall/test/PERVault.t.sol +++ b/per_multicall/test/PERVault.t.sol @@ -222,7 +222,8 @@ contract PERVaultTest is Test, Signatures { 110 * healthPrecision, 100 * healthPrecision, _idToken1, - _idToken2 + _idToken2, + new bytes[](0) ); _q1Depositor -= _q1Vault0; _q2Depositor += _q2Vault0; @@ -241,7 +242,8 @@ contract PERVaultTest is Test, Signatures { 110 * healthPrecision, 100 * healthPrecision, _idToken1, - _idToken2 + _idToken2, + new bytes[](0) ); _q1Depositor -= _q1Vault0; _q2Depositor += _q2Vault0; From f481b5f73deebc5d9ea88674b837bbc9656fe0f2 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 28 Jan 2024 11:21:46 +0100 Subject: [PATCH 08/41] Use price feed id as the name of WETH contract for consistency --- per_multicall/src/WETH9.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/per_multicall/src/WETH9.sol b/per_multicall/src/WETH9.sol index 53f2a3c3..c9972a27 100644 --- a/per_multicall/src/WETH9.sol +++ b/per_multicall/src/WETH9.sol @@ -20,7 +20,8 @@ pragma solidity ^0.8.0; contract WETH9 { - string public name = "Wrapped Ether"; + string public name = + "c96458d393fe9deb7a7d63a0ac41e2898a67a7750dbd166673279e06c868df0a"; // ETH/USD pricefeed id string public symbol = "WETH"; uint8 public decimals = 18; From 20cb96af764c08689030d0748f6cabadc1bb4f35 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 28 Jan 2024 11:22:19 +0100 Subject: [PATCH 09/41] Update docs --- per_multicall/README.md | 2 +- per_multicall/script/Vault.s.sol | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/per_multicall/README.md b/per_multicall/README.md index 3296a09d..03825d1d 100644 --- a/per_multicall/README.md +++ b/per_multicall/README.md @@ -37,7 +37,7 @@ $ forge script script/Vault.s.sol --via-ir --fork-url http://localhost:8545 --se 2. Set oracle prices to allow for vault creation. ```shell -$ forge script script/Vault.s.sol --via-ir --fork-url http://localhost:8545 --sender 0xd6e417287b875a3932c1ff5dcb26d4d2c8b90b40 --private-key 0xf46ea803192f16ef1c4f1d5fb0d6060535dbd571ea1afc7db6816f28961ba78a -vvv --sig 'setOraclePrice(int64,int64,uint64)' 110 110 190 --broadcast +$ forge script script/Vault.s.sol --via-ir --fork-url http://localhost:8545 --sender 0xd6e417287b875a3932c1ff5dcb26d4d2c8b90b40 -vvv --sig 'setOraclePrice(int64,int64,uint64)' 110 110 190 --broadcast ``` 3. Vault creation. diff --git a/per_multicall/script/Vault.s.sol b/per_multicall/script/Vault.s.sol index 7b7b0b65..9426db06 100644 --- a/per_multicall/script/Vault.s.sol +++ b/per_multicall/script/Vault.s.sol @@ -88,10 +88,10 @@ contract VaultScript is Script { } /** - @notice Sets up the testnet environment - deploys WETH, PER, LiquidationAdapter, TokenVault along with 5 ERC-20 tokens to use as collateral and debt tokens - The erc-20 tokens have their actual name as symbol and pyth price feed id as their name. A huge amount of these tokens are minted to the token vault - @param pyth The address of the already deployed pyth contract to use + @notice Sets up the testnet environment + deploys WETH, PER, LiquidationAdapter, TokenVault along with 5 ERC-20 tokens to use as collateral and debt tokens + The erc-20 tokens have their actual name as symbol and pyth price feed id as their name. A huge amount of these tokens are minted to the token vault + @param pyth The address of the already deployed pyth contract to use */ function setUpTestnet(address pyth) public { (, uint256 skanvil) = getAnvil(); From 1087605b45b378d780b0c775e923d98108cb5ab9 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 28 Jan 2024 11:24:15 +0100 Subject: [PATCH 10/41] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index cb1186e1..23021010 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ api_keys.py per_multicall/latestEnvironment.json **/target/ +node_modules +.idea From 80cef21738ef9c013e5bdabf4065d5ab8066d91d Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 28 Jan 2024 12:24:24 +0100 Subject: [PATCH 11/41] Update token vault searcher --- beacon/protocols/beacon_TokenVault.py | 365 +++++++++++++++----------- beacon/utils/pyth_prices.py | 206 ++++++++++----- 2 files changed, 353 insertions(+), 218 deletions(-) diff --git a/beacon/protocols/beacon_TokenVault.py b/beacon/protocols/beacon_TokenVault.py index 71bc3d88..ab6fd274 100644 --- a/beacon/protocols/beacon_TokenVault.py +++ b/beacon/protocols/beacon_TokenVault.py @@ -1,16 +1,24 @@ +import base64 import web3 from eth_abi import encode import json from typing import TypedDict +import argparse +import logging +import asyncio +import httpx -from beacon.utils.pyth_prices import * -from beacon.utils.types_liquidation_adapter import * +from beacon.utils.pyth_prices import PriceFeedClient, PriceFeed +from beacon.utils.types_liquidation_adapter import LiquidationOpportunity -TOKEN_VAULT_ADDRESS = "0x72A22FfcAfa6684d4EE449620270ac05afE963d0" -CHAIN_RPC_ENDPOINT = "http://localhost:8545" +class ProtocolAccount(TypedDict): + """ + ProtocolAccount is a TypedDict that represents an account/vault in the protocol. + + This class contains all the relevant information about a vault/account on this protocol that is necessary for identifying whether it is eligible for liquidation and constructing a LiquidationOpportunity object. + """ -class LiquidationAccount(TypedDict): account_number: int token_address_collateral: str token_address_debt: str @@ -23,164 +31,227 @@ class LiquidationAccount(TypedDict): def get_vault_abi(): - f = open('per_multicall/out/TokenVault.sol/TokenVault.json') + f = open("per_multicall/out/TokenVault.sol/TokenVault.json") data = json.load(f) - return data['abi'] + return data["abi"] -""" -get_accounts() is the first method that the protocol should implement. It should take no arguments and return all the open accounts in the protocol in the form of a list of objects of type LiquidationAccount (defined above). Each LiquidationAccount object represents an account/vault in the protocol. -This function can be implemented in any way, but it should be able to return all the open accounts in the protocol. For some protocols, this may be easily doable by just querying on-chain state; however, most protocols will likely need to maintain or access an off-chain indexer to get the list of all open accounts. -""" +class VaultMonitor: + def __init__(self, rpc_url: str, contract_address: str): + self.rpc_url = rpc_url + self.contract_address = contract_address + self.w3 = web3.AsyncWeb3(web3.AsyncHTTPProvider(rpc_url)) + self.token_vault = self.w3.eth.contract( + address=contract_address, abi=get_vault_abi() + ) + self.price_feed_client = PriceFeedClient([]) + + async def get_accounts(self) -> list[ProtocolAccount]: + """ + Returns all the open accounts in the protocol in the form of a list of type ProtocolAccount. + + Args: + rpc_url (str): The RPC URL of the chain + Returns: + List of objects of type ProtocolAccount (defined above). Each ProtocolAccount object represents an account/vault in the protocol. + """ + abi = get_vault_abi() + + j = 0 + while abi[j].get("name") != "getVault": + j += 1 + get_vault_details = abi[j]["outputs"][0]["components"] + vault_struct = [x["name"] for x in get_vault_details] + + accounts = [] + done = False + account_number = 0 + + while not done: + vault = await self.token_vault.functions.getVault(account_number).call() + vault_dict = dict(zip(vault_struct, vault)) + + if ( + int(vault_dict["tokenCollateral"], 16) == 0 + and int(vault_dict["tokenDebt"], 16) == 0 + ): + done = True + else: + account: ProtocolAccount = { + "account_number": account_number, + "token_address_collateral": vault_dict["tokenCollateral"], + "token_id_collateral": vault_dict["tokenIDCollateral"].hex(), + "token_address_debt": vault_dict["tokenDebt"], + "token_id_debt": vault_dict["tokenIDDebt"].hex(), + "amount_collateral": vault_dict["amountCollateral"], + "amount_debt": vault_dict["amountDebt"], + "min_health_ratio": vault_dict["minHealthRatio"], + "min_permissionless_health_ratio": vault_dict[ + "minPermissionLessHealthRatio" + ], + } + accounts.append(account) + account_number += 1 + + return accounts + + def create_liquidation_opp( + self, account: ProtocolAccount, prices: list[PriceFeed] + ) -> LiquidationOpportunity: + """ + Constructs a LiquidationOpportunity object from a ProtocolAccount object and a set of relevant Pyth PriceFeeds. + + Args: + account: A ProtocolAccount object, representing an account/vault in the protocol. + prices: A list of PriceFeed objects, representing the relevant Pyth price feeds for the tokens in the ProtocolAccount object. + Returns: + A LiquidationOpportunity object corresponding to the specified account. + """ + + price_updates = [base64.b64decode(update["vaa"]) for update in prices] + w3 = web3.Web3() + abi = get_vault_abi() + token_vault = w3.eth.contract(address=self.contract_address, abi=abi) + calldata = token_vault.encodeABI( + fn_name="liquidateWithPriceUpdate", + args=[account["account_number"], price_updates], + ) + permission_payload = encode(["uint256"], [account["account_number"]]) + permission = ( + "0x" + + encode( + ["address", "bytes"], [self.contract_address, permission_payload] + ).hex() + ) + opp: LiquidationOpportunity = { + "chain_id": "development", + "contract": self.contract_address, + "calldata": calldata, + "permission_key": permission, + "account": str(account["account_number"]), + "repay_tokens": [ + (account["token_address_debt"], str(account["amount_debt"])) + ], + "receipt_tokens": [ + (account["token_address_collateral"], + str(account["amount_collateral"])) + ], + } + + # TODO: figure out best interface to show partial liquidation possibility? Is this even important? + # NOTE: the above interface may work out fine for single collateral, + # single debt vaults, since most of them just have proportional (linear) + # liquidation amount functions. But may not work well for multi-asset + # vaults bc users may need to do out the price calculations themselves. + + return opp + + async def get_liquidation_opportunities(self) -> (list[LiquidationOpportunity]): + """ + Filters list of ProtocolAccount types to return a list of LiquidationOpportunity types. + + Args: + accounts: A list of ProtocolAccount objects, representing all the open accounts in the protocol. + prices: A dictionary of Pyth price feeds, where the keys are Pyth feed IDs and the values are PriceFeed objects. + Returns: + A list of LiquidationOpportunity objects, one per account that is eligible for liquidation. + """ + + liquidatable = [] + accounts = await self.get_accounts() + for account in accounts: + # TODO: optimize this to only query for the price feeds that are needed and only query once + ( + price_collateral, + price_debt, + ) = await self.price_feed_client.get_pyth_prices_latest( + [account["token_id_collateral"], account["token_id_debt"]] + ) + if price_collateral is None: + raise Exception( + f"Price for collateral token {account['token_id_collateral']} not found" + ) + + if price_debt is None: + raise Exception( + f"Price for debt token {account['token_id_debt']} not found" + ) + + value_collateral = ( + int(price_collateral["price"]["price"]) * + account["amount_collateral"] + ) + value_debt = int(price_debt["price"] + ["price"]) * account["amount_debt"] + if ( + value_debt * int(account["min_health_ratio"]) + > value_collateral * 10**18 + ): + price_updates = [price_collateral, price_debt] + liquidatable.append( + self.create_liquidation_opp(account, price_updates)) + + return liquidatable -async def get_accounts() -> list[LiquidationAccount]: - abi = get_vault_abi() - w3 = web3.AsyncWeb3(web3.AsyncHTTPProvider(CHAIN_RPC_ENDPOINT)) - token_vault = w3.eth.contract( - address=TOKEN_VAULT_ADDRESS, - abi=abi) - j = 0 - while abi[j].get('name') != 'getVault': - j += 1 - get_vault_details = abi[j]['outputs'][0]['components'] - vault_struct = [x['name'] for x in get_vault_details] +async def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--rpc-url", + type=str, + required=True, + help="Chain RPC endpoint, used to fetch on-chain data via get_accounts", + ) + parser.add_argument( + "--vault-contract", + type=str, + required=True, + dest="vault_contract", + help="Token vault contract address", + ) + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument( + "--dry-run", + action="store_false", + dest="send_beacon", + help="If provided, will not send liquidation opportunities to the beacon server", + ) + group.add_argument( + "--beacon-server-url", + type=str, + help="Beacon server endpoint; if provided, will send liquidation opportunities to the beacon server", + ) + args = parser.parse_args() - accounts = [] - done = False - account_number = 0 + logging.basicConfig(level=logging.INFO) + logging.getLogger("httpx").propagate = False - while not done: - vault = await token_vault.functions.getVault(account_number).call() - vault_dict = dict(zip(vault_struct, vault)) + monitor = VaultMonitor(args.rpc_url, args.vault_contract) - if int( - vault_dict['tokenCollateral'], - 16) == 0 and int( - vault_dict['tokenDebt'], - 16) == 0: - done = True - else: - account: LiquidationAccount = { - "account_number": account_number, - "token_address_collateral": vault_dict['tokenCollateral'], - "token_id_collateral": vault_dict['tokenIDCollateral'].hex(), - "token_address_debt": vault_dict['tokenDebt'], - "token_id_debt": vault_dict['tokenIDDebt'].hex(), - "amount_collateral": vault_dict['amountCollateral'], - "amount_debt": vault_dict['amountDebt'], - "min_health_ratio": vault_dict['minHealthRatio'], - "min_permissionless_health_ratio": vault_dict['minPermissionLessHealthRatio']} - accounts.append(account) - account_number += 1 - - return accounts - - -def create_liquidation_opp( - account: LiquidationAccount, prices: list[PriceFeed] -) -> LiquidationOpportunity: - # [bytes.fromhex(update['vaa']) for update in prices] ## TODO: uncomment this, to add back price updates - price_updates = [] - function_signature = web3.Web3.solidity_keccak( - ["string"], ["liquidateWithPriceUpdate(uint256,bytes[])"] - )[:4].hex() - calldata = ( - function_signature - + encode( - ["uint256", "bytes[]"], [account["account_number"], price_updates] - ).hex() - ) + while True: + opportunities = await monitor.get_liquidation_opportunities() - msg = encode(["uint256"], [account["account_number"]]) - permission = "0x" + encode(["address", "bytes"], - [TOKEN_VAULT_ADDRESS, msg]).hex() - - opp: LiquidationOpportunity = { - "chain_id": "development", - "contract": TOKEN_VAULT_ADDRESS, - "calldata": calldata, - "permission_key": permission, - "account": str(account["account_number"]), - "repay_tokens": [ - { - "contract": account["token_address_debt"], - "amount": str(account["amount_debt"]), - } - ], - "receipt_tokens": [ - { - "contract": account["token_address_collateral"], - "amount": str(account["amount_collateral"]), - } - ] - } - - # TODO: figure out best interface to show partial liquidation possibility? Is this even important? - # NOTE: the above interface may work out fine for single collateral, - # single debt vaults, since most of them just have proportional (linear) - # liquidation amount functions. But may not work well for multi-asset - # vaults bc users may need to do out the price calculations themselves. - - return opp - - -""" -get_liquidatable(accounts, prices) is the second method that the protocol should implement. It should take two arguments: account--a list of Account (defined above) objects--and prices--a dictionary of Pyth prices. -accounts should be the list of all open accounts in the protocol (i.e. the output of get_accounts()). -prices should be a dictionary of Pyth prices, where the keys are Pyth feed IDs and the values are PriceFeed objects. prices can be retrieved from the provided price retrieval functions. -This function should return a lists of liquidation opportunities. Each opportunity should be of the form LiquidationOpportunity defined above. -""" - - -def get_liquidatable( - accounts: list[LiquidationAccount], prices: dict[str, PriceFeed] -) -> list[LiquidationOpportunity]: - liquidatable = [] - - for account in accounts: - price_collateral = prices[account["token_id_collateral"]] - price_debt = prices[account["token_id_debt"]] - - value_collateral = ( - int(price_collateral["price"]["price"]) * - account["amount_collateral"] - ) - value_debt = int(price_debt["price"]["price"]) * account["amount_debt"] + if args.send_beacon: + client = httpx.AsyncClient() + for opp in opportunities: + resp = await client.post(args.beacon_server_url, json=opp) + if resp.status_code == 200: + logging.info("Successfully posted to beacon") + else: + logging.error( + f"Failed to post to beacon, status code: {resp.status_code}, response: {resp.text}" + ) - if value_debt * int(account["min_health_ratio"]) > value_collateral * 10**18: - print("unhealthy vault") - print( - value_debt * int(account["min_health_ratio"]), - value_collateral * 10**18, + else: + logging.info( + f"List of liquidatable accounts:\n{json.dumps(opportunities, indent=2)}" ) - price_updates = [price_collateral, price_debt] - liquidatable.append(create_liquidation_opp(account, price_updates)) - return liquidatable + await asyncio.sleep(1) -async def main(): - # get all accounts - accounts = await get_accounts() - - # get prices - pyth_price_feed_ids = await get_price_feed_ids() - pyth_prices_latest = [] - i = 0 - cntr = 100 - while len(pyth_price_feed_ids[i:i + cntr]) > 0: - pyth_prices_latest += await get_pyth_prices_latest(pyth_price_feed_ids[i:i + cntr]) - i += cntr - pyth_prices_latest = dict(pyth_prices_latest) - - # get liquidatable accounts - liquidatable = get_liquidatable(accounts, pyth_prices_latest) - - print(liquidatable) - if __name__ == "__main__": asyncio.run(main()) diff --git a/beacon/utils/pyth_prices.py b/beacon/utils/pyth_prices.py index f8a7f3c1..7e7243e5 100644 --- a/beacon/utils/pyth_prices.py +++ b/beacon/utils/pyth_prices.py @@ -2,99 +2,163 @@ import asyncio from typing import TypedDict -HERMES_ENDPOINT = "https://hermes.pyth.network/api/" +HERMES_ENDPOINT_HTTPS = "https://hermes.pyth.network/api/" +HERMES_ENDPOINT_WSS = "wss://hermes.pyth.network/ws" class Price(TypedDict): - price: int - conf: int + price: str + conf: str expo: int publish_time: int class PriceFeed(TypedDict): - feed_id: str + id: str price: Price - price_ema: Price + ema_price: Price vaa: str -CLIENT = httpx.AsyncClient() - - -def extract_price_feed(data: dict) -> PriceFeed: - price: Price = data['price'] - price_ema: Price = data['ema_price'] - vaa = data['vaa'] - price_feed: PriceFeed = { - "feed_id": data['id'], - "price": price, - "price_ema": price_ema, - "vaa": vaa - } - return price_feed - - async def get_price_feed_ids() -> list[str]: - url = HERMES_ENDPOINT + "price_feed_ids" - - data = (await CLIENT.get(url)).json() - - return data - - -async def get_pyth_prices_latest( - feedIds: list[str] -) -> list[tuple[str, PriceFeed]]: - url = HERMES_ENDPOINT + "latest_price_feeds?" - params = {"ids[]": feedIds, "binary": "true"} + """ + Queries the Hermes https endpoint for a list of the IDs of all Pyth price feeds. + """ - data = (await CLIENT.get(url, params=params)).json() + url = HERMES_ENDPOINT_HTTPS + "price_feed_ids" + client = httpx.AsyncClient() - results = [] - for res in data: - price_feed = extract_price_feed(res) - results.append((res['id'], price_feed)) + data = (await client.get(url)).json() - return results - - -async def get_pyth_price_at_time( - feed_id: str, - timestamp: int -) -> tuple[str, PriceFeed]: - url = HERMES_ENDPOINT + f"get_price_feed" - params = {"id": feed_id, "publish_time": timestamp, "binary": "true"} - - data = (await CLIENT.get(url, params=params)).json() - - price_feed = extract_price_feed(data) - - return (feed_id, price_feed) - - -async def get_all_prices() -> dict[str, PriceFeed]: - pyth_price_feed_ids = await get_price_feed_ids() + return data - pyth_prices_latest = [] - i = 0 - cntr = 100 - while len(pyth_price_feed_ids[i:i + cntr]) > 0: - pyth_prices_latest += await get_pyth_prices_latest(pyth_price_feed_ids[i:i + cntr]) - i += cntr - return dict(pyth_prices_latest) +class PriceFeedClient: + def __init__(self, feed_ids: list[str]): + self.feed_ids = feed_ids + self.pending_feed_ids = feed_ids + self.prices_dict: dict[str, PriceFeed] = {} + self.client = httpx.AsyncClient() + + def add_feed_ids(self, feed_ids: list[str]): + self.feed_ids += feed_ids + self.feed_ids = list(set(self.feed_ids)) + self.pending_feed_ids += feed_ids + + def extract_price_feed(self, data: dict) -> PriceFeed: + """ + Extracts a PriceFeed object from the JSON response from Hermes. + """ + price = data['price'] + price_ema = data['ema_price'] + vaa = data['vaa'] + price_feed = { + "feed_id": data['id'], + "price": price, + "price_ema": price_ema, + "vaa": vaa + } + return price_feed + + async def get_pyth_prices_latest( + self, + feedIds: list[str] + ) -> list[PriceFeed]: + """ + Queries the Hermes https endpoint for the latest price feeds for a list of Pyth feed IDs. + """ + url = HERMES_ENDPOINT_HTTPS + "latest_price_feeds?" + params = {"ids[]": feedIds, "binary": "true"} + + data = (await self.client.get(url, params=params)).json() + + results = [] + for res in data: + price_feed = self.extract_price_feed(res) + results.append(price_feed) + + return results + + async def get_pyth_price_at_time( + self, + feed_id: str, + timestamp: int + ) -> PriceFeed: + """ + Queries the Hermes https endpoint for the price feed for a Pyth feed ID at a given timestamp. + """ + url = HERMES_ENDPOINT_HTTPS + f"get_price_feed" + params = {"id": feed_id, "publish_time": timestamp, "binary": "true"} + + data = (await self.client.get(url, params=params)).json() + + price_feed = self.extract_price_feed(data) + + return price_feed + + async def get_all_prices(self) -> dict[str, PriceFeed]: + """ + Queries the Hermes http endpoint for the latest price feeds for all feed IDs in the class object. + + There are limitations on the number of feed IDs that can be queried at once, so this function queries the feed IDs in batches. + """ + pyth_prices_latest = [] + i = 0 + batch_size = 100 + while len(self.feed_ids[i:i + batch_size]) > 0: + pyth_prices_latest += await self.get_pyth_prices_latest(self.feed_ids[i:i + batch_size]) + i += batch_size + + return dict(pyth_prices_latest) + + async def ws_pyth_prices(self): + """ + Opens a websocket connection to Hermes for latest prices for all feed IDs in the class object. + """ + import json + import websockets + + async with websockets.connect(HERMES_ENDPOINT_WSS) as ws: + while True: + if len(self.pending_feed_ids) > 0: + json_subscribe = { + "ids": self.pending_feed_ids, + "type": "subscribe", + "verbose": True, + "binary": True + } + await ws.send(json.dumps(json_subscribe)) + self.pending_feed_ids = [] + + msg = json.loads(await ws.recv()) + if msg["type"] == "response": + if msg["status"] != "success": + raise Exception("Error in subscribing to websocket") + try: + if msg["type"] != "price_update": + continue + + feed_id = msg["price_feed"]["id"] + new_feed = msg["price_feed"] + + self.prices_dict[feed_id] = new_feed + + except: + raise Exception("Error in price_update message", msg) async def main(): - pyth_price = await get_pyth_price_at_time("0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace", 1703016621) + feed_ids = await get_price_feed_ids() + # TODO: remove this line, once rate limits are figured out + feed_ids = feed_ids[:1] + price_feed_client = PriceFeedClient(feed_ids) - data = await get_all_prices() + print("Starting web socket...") + ws_call = price_feed_client.ws_pyth_prices() + asyncio.create_task(ws_call) - return pyth_price, data + while True: + await asyncio.sleep(1) if __name__ == "__main__": - pyth_price, data = asyncio.run(main()) - - import pdb - pdb.set_trace() + asyncio.run(main()) From 2efc4ebbb9371d9d0ac0130c78ebe4799d552dde Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Mon, 29 Jan 2024 10:37:42 +0100 Subject: [PATCH 12/41] Add value field to Adapter structs and logic --- auction-server/src/api/marketplace.rs | 6 ++++++ auction-server/src/liquidation_adapter.rs | 2 ++ auction-server/src/state.rs | 1 + beacon/protocols/beacon_TokenVault.py | 1 + beacon/surface_opportunities.py | 2 +- per_multicall/script/Vault.s.sol | 7 +++---- per_multicall/src/Errors.sol | 2 ++ per_multicall/src/LiquidationAdapter.sol | 25 ++++++++++++++++++----- per_multicall/src/Structs.sol | 1 + 9 files changed, 37 insertions(+), 10 deletions(-) diff --git a/auction-server/src/api/marketplace.rs b/auction-server/src/api/marketplace.rs index b16ef2fb..12a1d6c4 100644 --- a/auction-server/src/api/marketplace.rs +++ b/auction-server/src/api/marketplace.rs @@ -54,6 +54,9 @@ pub struct LiquidationOpportunity { /// Calldata for the contract call. #[schema(example = "0xdeadbeef", value_type=String)] calldata: Bytes, + /// The value to send with the contract call. + #[schema(example = "1")] + value: String, repay_tokens: Vec, receipt_tokens: Vec, @@ -111,6 +114,8 @@ pub async fn submit_opportunity( permission_key: opportunity.permission_key, contract: opportunity.contract, calldata: opportunity.calldata, + value: U256::from_dec_str(opportunity.value.as_str()) + .map_err(|_| RestError::BadParameters("Invalid value".to_string()))?, repay_tokens, receipt_tokens, }, @@ -139,6 +144,7 @@ pub async fn fetch_opportunities( chain_id: opportunity.chain_id, contract: opportunity.contract, calldata: opportunity.calldata, + value: opportunity.value.to_string(), repay_tokens: opportunity .repay_tokens .into_iter() diff --git a/auction-server/src/liquidation_adapter.rs b/auction-server/src/liquidation_adapter.rs index 0ddaa117..c6cf4ccf 100644 --- a/auction-server/src/liquidation_adapter.rs +++ b/auction-server/src/liquidation_adapter.rs @@ -49,6 +49,7 @@ pub fn verify_signature(params: liquidation_adapter::LiquidationCallParams) -> R params.expected_receipt_tokens.into_token(), params.contract_address.into_token(), params.data.into_token(), + params.value.into_token(), params.bid.into_token(), ]); let nonce = params.valid_until; @@ -88,6 +89,7 @@ pub fn make_liquidator_calldata( liquidator: bid.liquidator, contract_address: opportunity.contract, data: opportunity.calldata, + value: opportunity.value, valid_until: bid.valid_until, bid: bid.bid_amount, signature_liquidator: bid.signature.to_vec().into(), diff --git a/auction-server/src/state.rs b/auction-server/src/state.rs index f247c81d..ac7bced6 100644 --- a/auction-server/src/state.rs +++ b/auction-server/src/state.rs @@ -37,6 +37,7 @@ pub struct VerifiedLiquidationOpportunity { pub permission_key: PermissionKey, pub contract: Address, pub calldata: Bytes, + pub value: U256, pub repay_tokens: Vec<(Address, U256)>, pub receipt_tokens: Vec<(Address, U256)>, } diff --git a/beacon/protocols/beacon_TokenVault.py b/beacon/protocols/beacon_TokenVault.py index ab6fd274..70c0eb27 100644 --- a/beacon/protocols/beacon_TokenVault.py +++ b/beacon/protocols/beacon_TokenVault.py @@ -132,6 +132,7 @@ def create_liquidation_opp( "calldata": calldata, "permission_key": permission, "account": str(account["account_number"]), + "value": str(len(price_updates)), "repay_tokens": [ (account["token_address_debt"], str(account["amount_debt"])) ], diff --git a/beacon/surface_opportunities.py b/beacon/surface_opportunities.py index 0aad9b0d..d891f031 100644 --- a/beacon/surface_opportunities.py +++ b/beacon/surface_opportunities.py @@ -26,7 +26,7 @@ async def main(): for protocol in PROTOCOLS: accounts = await protocol.get_accounts() - liquidatable_protocol = protocol.get_liquidatable( + liquidatable_protocol = protocol.get_liquidation_opportunities( accounts, pyth_prices_latest) liquidatable += liquidatable_protocol diff --git a/per_multicall/script/Vault.s.sol b/per_multicall/script/Vault.s.sol index 9426db06..8b3c72e2 100644 --- a/per_multicall/script/Vault.s.sol +++ b/per_multicall/script/Vault.s.sol @@ -99,7 +99,6 @@ contract VaultScript is Script { address weth = deployWeth(); (address per, address liquidationAdapter) = deployPER(weth); address vault = deployVault(per, pyth); - vm.startBroadcast(skanvil); address[] memory tokens = new address[](5); uint256 lots_of_money = 10 ** 36; tokens[0] = address( @@ -133,15 +132,15 @@ contract VaultScript is Script { ) ); for (uint i = 0; i < 5; i++) { - MyToken(tokens[i]).mint(tokenVault, lots_of_money); + MyToken(tokens[i]).mint(vault, lots_of_money); } vm.stopBroadcast(); string memory obj = ""; vm.serializeAddress(obj, "tokens", tokens); vm.serializeAddress(obj, "per", per); vm.serializeAddress(obj, "liquidationAdapter", liquidationAdapter); - vm.serializeAddress(obj, "oracle", oracle); - vm.serializeAddress(obj, "tokenVault", tokenVault); + vm.serializeAddress(obj, "oracle", pyth); + vm.serializeAddress(obj, "tokenVault", vault); string memory finalJSON = vm.serializeAddress(obj, "weth", weth); vm.writeJson(finalJSON, latestEnvironmentPath); } diff --git a/per_multicall/src/Errors.sol b/per_multicall/src/Errors.sol index 435cd3aa..d229f5c7 100644 --- a/per_multicall/src/Errors.sol +++ b/per_multicall/src/Errors.sol @@ -11,6 +11,8 @@ error ExpiredSignature(); error SignatureAlreadyUsed(); +error InsufficientWETHForMsgValue(); + error InvalidPERSignature(); error InvalidTimestamp(); diff --git a/per_multicall/src/LiquidationAdapter.sol b/per_multicall/src/LiquidationAdapter.sol index 50e55519..5e0a7a84 100644 --- a/per_multicall/src/LiquidationAdapter.sol +++ b/per_multicall/src/LiquidationAdapter.sol @@ -69,6 +69,7 @@ contract LiquidationAdapter is SigVerify { params.expectedReceiptTokens, params.contractAddress, params.data, + params.value, params.bid ), params.validUntil, @@ -88,6 +89,7 @@ contract LiquidationAdapter is SigVerify { params.expectedReceiptTokens.length ); + address weth = getWeth(); // transfer repay tokens to this contract for (uint i = 0; i < params.repayTokens.length; i++) { IERC20 token = IERC20(params.repayTokens[i].token); @@ -99,7 +101,17 @@ contract LiquidationAdapter is SigVerify { ); // approve contract to spend repay tokens - token.approve(params.contractAddress, params.repayTokens[i].amount); + uint256 approveAmount = params.repayTokens[i].amount; + if (params.repayTokens[i].token == weth) { + if (approveAmount >= params.value) { + // we need `parmas.value` of to be sent to the contract directly + // so this amount should be subtracted from the approveAmount + approveAmount = approveAmount - params.value; + } else { + revert InsufficientWETHForMsgValue(); + } + } + token.approve(params.contractAddress, approveAmount); } // get balances of receipt tokens before call @@ -111,10 +123,14 @@ contract LiquidationAdapter is SigVerify { token.balanceOf(address(this)) + amount; } + if (params.value > 0) { + // unwrap weth to eth to use in call + WETH9(payable(weth)).withdraw(params.value); + } - (bool success, bytes memory reason) = params.contractAddress.call( - params.data - ); + (bool success, bytes memory reason) = params.contractAddress.call{ + value: params.value + }(params.data); if (!success) { string memory revertData = _getRevertMsg(reason); @@ -137,7 +153,6 @@ contract LiquidationAdapter is SigVerify { } // transfer bid to PER adapter in the form of weth - address weth = getWeth(); WETH9(payable(weth)).transferFrom( params.liquidator, address(this), diff --git a/per_multicall/src/Structs.sol b/per_multicall/src/Structs.sol index 7b1e5423..aec0ba7b 100644 --- a/per_multicall/src/Structs.sol +++ b/per_multicall/src/Structs.sol @@ -35,6 +35,7 @@ struct LiquidationCallParams { address liquidator; address contractAddress; bytes data; + uint256 value; uint256 validUntil; uint256 bid; bytes signatureLiquidator; From a7bb735123e428ff639f436ce5a86a08de09bce0 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 11:14:45 +0100 Subject: [PATCH 13/41] Add new command to setup an already funded searcher account --- vault-simulator/src/config.rs | 39 ++++++--- vault-simulator/src/main.rs | 3 + vault-simulator/src/simulator.rs | 139 +++++++++++++++++++------------ 3 files changed, 116 insertions(+), 65 deletions(-) diff --git a/vault-simulator/src/config.rs b/vault-simulator/src/config.rs index e266fa1d..3eaf98f8 100644 --- a/vault-simulator/src/config.rs +++ b/vault-simulator/src/config.rs @@ -1,21 +1,13 @@ use { - anyhow::Result, clap::{ crate_authors, crate_description, crate_name, crate_version, - Arg, - ArgAction, Args, Parser, }, ethers::abi::Address, - std::{ - collections::HashMap, - fs, - net::SocketAddr, - }, url::Url, }; @@ -28,7 +20,10 @@ use { #[allow(clippy::large_enum_variant)] pub enum Options { /// Run the simulator. - Run(RunOptions), + Run(SimulatorOptions), + + /// Setup an already funded searcher account with ERC20 tokens and WETH. + CreateSearcher(SearcherOptions), /// Deploy the token vault contract. Deploy(DeployOptions), @@ -46,10 +41,6 @@ pub struct RunOptions { #[arg(env = "PRIVATE_KEY")] pub private_key: String, - /// The address of the contract to interact with. - #[arg(long = "contract")] - pub contract: Address, - #[arg(long = "token")] pub tokens: Vec
, @@ -57,6 +48,28 @@ pub struct RunOptions { pub weth: Address, } +#[derive(Args, Clone, Debug)] +pub struct SimulatorOptions { + /// Server Options + #[command(flatten)] + pub run_options: RunOptions, + + /// The address of the token vault contract to interact with + #[arg(long = "vault-contract")] + pub vault_contract: Address, +} + +#[derive(Args, Clone, Debug)] +pub struct SearcherOptions { + /// Server Options + #[command(flatten)] + pub run_options: RunOptions, + + /// The address of the liquidation adapter contract to use for approvals + #[arg(long = "adapter-contract")] + pub adapter_contract: Address, +} + #[derive(Args, Clone, Debug)] pub struct DeployOptions { /// Address and port the server will bind to. diff --git a/vault-simulator/src/main.rs b/vault-simulator/src/main.rs index 0282d498..cfc3e13c 100644 --- a/vault-simulator/src/main.rs +++ b/vault-simulator/src/main.rs @@ -35,6 +35,9 @@ async fn main() -> Result<()> { config::Options::Run(opts) => { simulator::run_simulator(opts).await?; } + config::Options::CreateSearcher(opts) => { + simulator::create_searcher(opts).await?; + } config::Options::Deploy(opts) => { simulator::deploy_contract(opts).await?; } diff --git a/vault-simulator/src/simulator.rs b/vault-simulator/src/simulator.rs index 1bc4bb45..fc71ad15 100644 --- a/vault-simulator/src/simulator.rs +++ b/vault-simulator/src/simulator.rs @@ -1,7 +1,8 @@ use { crate::config::{ DeployOptions, - RunOptions, + SearcherOptions, + SimulatorOptions, }, anyhow::{ anyhow, @@ -36,7 +37,10 @@ use { seq::SliceRandom, }, serde_json::Value, - std::sync::Arc, + std::{ + sync::Arc, + time::Duration, + }, url::Url, }; @@ -46,6 +50,7 @@ abigen!( ); abigen!(ERC20, "../per_multicall/out/MyToken.sol/MyToken.json"); +abigen!(WETH9, "../per_multicall/out/WETH9.sol/WETH9.json"); abigen!(IPyth, "../per_multicall/out/IPyth.sol/IPyth.json"); pub type SignableTokenVaultContract = TokenVault, LocalWallet>>; @@ -96,6 +101,31 @@ fn parse_update(update: Value) -> Result { }) } +async fn setup_client( + private_key: String, + rpc_address: Url, +) -> Result, LocalWallet>>> { + let wallet = private_key + .parse::() + .map_err(|e| anyhow!("Can not parse private key: {}", e))?; + tracing::info!("Using wallet address: {}", wallet.address().to_string()); + let mut provider = Provider::::try_from(rpc_address.as_str()).map_err(|err| { + anyhow!( + "Failed to connect to {rpc_addr}: {:?}", + err, + rpc_addr = rpc_address.as_str() + ) + })?; + provider.set_interval(Duration::from_secs(1)); + let chain_id = provider.get_chainid().await?; + tracing::info!("Connected to chain: {}", chain_id); + let client = Arc::new(SignerMiddleware::new( + provider, + wallet.with_chain_id(chain_id.as_u64()), + )); + Ok(client) +} + async fn get_latest_updates(feed_ids: Vec) -> Result> { let url = Url::parse_with_params( "https://hermes.pyth.network/api/latest_price_feeds?verbose=true&binary=true", @@ -115,32 +145,13 @@ async fn get_latest_updates(feed_ids: Vec) -> Result> { .collect() } -pub async fn run_simulator(options: RunOptions) -> Result<()> { - let wallet = options - .private_key - .parse::() - .map_err(|e| anyhow!("Can not parse private key: {}", e))?; - tracing::info!("Using wallet address: {}", wallet.address().to_string()); - let provider = Provider::::try_from(options.rpc_addr.as_str()).map_err(|err| { - anyhow!( - "Failed to connect to {rpc_addr}: {:?}", - err, - rpc_addr = options.rpc_addr - ) - })?; - let chain_id = provider.get_chainid().await?; - tracing::info!("Connected to chain: {}", chain_id); - - // check the balance of the wallet - let wallet_address = wallet.address(); - let balance = provider.get_balance(wallet_address, None).await?; +pub async fn run_simulator(simulator_options: SimulatorOptions) -> Result<()> { + let options = simulator_options.run_options; + let client = setup_client(options.private_key, options.rpc_addr).await?; + let wallet_address = client.signer().address(); + let balance = client.get_balance(wallet_address, None).await?; tracing::info!("Wallet balance: {}", balance); - let client = Arc::new(SignerMiddleware::new( - provider, - wallet.with_chain_id(chain_id.as_u64()), - )); - let sample: [&Address; 2] = options .tokens .choose_multiple(&mut rand::thread_rng(), 2) @@ -172,16 +183,15 @@ pub async fn run_simulator(options: RunOptions) -> Result<()> { let collateral_update = updates[0].clone(); let debt_update = updates[1].clone(); - // usd value random between 100 and 1000 dollars let precision = U256::exp10(18); + // usd value random between 100 and 1000 dollars let collateral_value_usd: U256 = precision * U256::from(random::() % 900 + 100); tracing::info!("Collateral value usd: {}", collateral_value_usd); - tracing::info!("Collateral price: {}", collateral_update.price); tracing::info!("Debt price: {}", collateral_update.price); let amount_collateral: U256 = - collateral_value_usd * precision * 111 / 100 / collateral_update.price; // 10% more safety margin + collateral_value_usd * precision * 1100001 / 1000000 / collateral_update.price; // Slightly more than 110% to make sure the vault is created let amount_debt = collateral_value_usd * precision / debt_update.price; let min_health_ratio = U256::exp10(18) * 110 / 100; @@ -190,24 +200,25 @@ pub async fn run_simulator(options: RunOptions) -> Result<()> { let token_id_collateral: [u8; 32] = <[u8; 32]>::from_hex(collateral_info.price_id).unwrap(); let token_id_debt: [u8; 32] = <[u8; 32]>::from_hex(debt_info.price_id).unwrap(); let update_data = vec![collateral_update.vaa, debt_update.vaa]; - // let update_data = vec![]; collateral_info .contract .mint(wallet_address, amount_collateral) .send() + .await? .await?; collateral_info .contract - .approve(options.contract, amount_collateral) + .approve(simulator_options.vault_contract, amount_collateral) .send() + .await? .await?; - tracing::info!("Calling create_vault"); tracing::info!("Amount collateral: {}", amount_collateral); tracing::info!("Amount debt: {}", amount_debt); - let contract = SignableTokenVaultContract::new(options.contract, client.clone()); + let contract = + SignableTokenVaultContract::new(simulator_options.vault_contract, client.clone()); let tx = contract .create_vault( collateral_info.address, @@ -236,25 +247,7 @@ pub async fn run_simulator(options: RunOptions) -> Result<()> { } pub async fn deploy_contract(options: DeployOptions) -> Result<()> { - let wallet = options - .private_key - .parse::() - .map_err(|e| anyhow!("Can not parse private key: {}", e))?; - tracing::info!("Using wallet address: {}", wallet.address().to_string()); - let provider = Provider::::try_from(options.rpc_addr.as_str()).map_err(|err| { - anyhow!( - "Failed to connect to {rpc_addr}: {:?}", - err, - rpc_addr = options.rpc_addr - ) - })?; - let chain_id = provider.get_chainid().await?; - tracing::info!("Connected to chain id: {}", chain_id); - - let client = Arc::new(SignerMiddleware::new( - provider, - wallet.with_chain_id(chain_id.as_u64()), - )); + let client = setup_client(options.private_key, options.rpc_addr).await?; let contract = SignableTokenVaultContract::deploy( client, (options.per_contract, options.oracle_contract), @@ -264,3 +257,45 @@ pub async fn deploy_contract(options: DeployOptions) -> Result<()> { tracing::info!("{}", contract.address().to_string()); Ok(()) } + +pub async fn create_searcher(searcher_options: SearcherOptions) -> Result<()> { + let options = searcher_options.run_options; + let client = setup_client(options.private_key, options.rpc_addr).await?; + let wallet_address = client.signer().address(); + for token in options.tokens.iter() { + let token_contract = ERC20::new(*token, client.clone()); + token_contract + .approve(searcher_options.adapter_contract, U256::MAX) + .send() + .await? + .await?; + token_contract + .mint(wallet_address, U256::exp10(36)) + .send() + .await? + .await?; + tracing::info!( + "Token {} minted and approved to use by liquidation adapter", + token.to_string() + ); + } + + let weth_contract = WETH9::new(options.weth, client.clone()); + weth_contract + .deposit() + .value(U256::exp10(18)) + .send() + .await? + .await?; + weth_contract + .approve(searcher_options.adapter_contract, U256::MAX) + .send() + .await? + .await?; + let balance = weth_contract.balance_of(wallet_address).await?; + tracing::info!( + "1 ETH deposited into WETH and approved to use by liquidation adapter, current balance: {}", + balance + ); + Ok(()) +} From d7b2c2168c74d2ae3195baba143cf6a2a0614d19 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 11:43:49 +0100 Subject: [PATCH 14/41] Clean up errros and add signatures --- per_multicall/script/Vault.s.sol | 2 +- per_multicall/src/Errors.sol | 20 ++++++++++---------- per_multicall/src/LiquidationAdapter.sol | 1 + per_multicall/src/SigVerify.sol | 2 ++ per_multicall/src/TokenVault.sol | 4 ++-- per_multicall/src/TokenVaultErrors.sol | 10 ++++++++++ 6 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 per_multicall/src/TokenVaultErrors.sol diff --git a/per_multicall/script/Vault.s.sol b/per_multicall/script/Vault.s.sol index 8b3c72e2..0eea6a52 100644 --- a/per_multicall/script/Vault.s.sol +++ b/per_multicall/script/Vault.s.sol @@ -93,7 +93,7 @@ contract VaultScript is Script { The erc-20 tokens have their actual name as symbol and pyth price feed id as their name. A huge amount of these tokens are minted to the token vault @param pyth The address of the already deployed pyth contract to use */ - function setUpTestnet(address pyth) public { + function setupTestnet(address pyth) public { (, uint256 skanvil) = getAnvil(); vm.startBroadcast(skanvil); address weth = deployWeth(); diff --git a/per_multicall/src/Errors.sol b/per_multicall/src/Errors.sol index d229f5c7..ca8a0606 100644 --- a/per_multicall/src/Errors.sol +++ b/per_multicall/src/Errors.sol @@ -1,32 +1,32 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; -error NotPEROperator(); - +// Signature: 0x82b42900 error Unauthorized(); +// Signature: 0xf136a5b7 error InvalidSearcherSignature(); +// Signature: 0xdf4cc36d error ExpiredSignature(); +// Signature: 0x900bb2c9 error SignatureAlreadyUsed(); +// Signature: 0xee97c593 error InsufficientWETHForMsgValue(); +// Signature: 0x729f3230 error InvalidPERSignature(); +// Signature: 0xb7d09497 error InvalidTimestamp(); -error UncollateralizedVaultCreation(); - -error InvalidVaultUpdate(); - -error InvalidLiquidation(); - +// Signature: 0xc6388ef7 error InvalidBid(); +// Signature: 0xaba47339 error NotRegistered(); +// Signature: 0xd3c8346c error LiquidationCallFailed(string reason); - -error BogusContract(); diff --git a/per_multicall/src/LiquidationAdapter.sol b/per_multicall/src/LiquidationAdapter.sol index 5e0a7a84..b785f081 100644 --- a/per_multicall/src/LiquidationAdapter.sol +++ b/per_multicall/src/LiquidationAdapter.sol @@ -125,6 +125,7 @@ contract LiquidationAdapter is SigVerify { } if (params.value > 0) { // unwrap weth to eth to use in call + // TODO: Wrap in try catch and throw a revert with a better error since WETH9 reverts do not return a reason WETH9(payable(weth)).withdraw(params.value); } diff --git a/per_multicall/src/SigVerify.sol b/per_multicall/src/SigVerify.sol index da80323b..6edfea16 100644 --- a/per_multicall/src/SigVerify.sol +++ b/per_multicall/src/SigVerify.sol @@ -12,6 +12,7 @@ contract SigVerify { return keccak256(abi.encodePacked(_message, _nonce)); } + // TODO: This should not be here if only used on tests function getPERSignedMessageDigest( bytes32 _messageHash ) public pure returns (bytes32) { @@ -29,6 +30,7 @@ contract SigVerify { bytes memory _data, uint _nonce ) public pure returns (bytes32) { + // TODO: fold nonce back to the rest of data, it does not need to be treated differently return keccak256(abi.encodePacked(_data, _nonce)); } diff --git a/per_multicall/src/TokenVault.sol b/per_multicall/src/TokenVault.sol index 5651c01c..69d18422 100644 --- a/per_multicall/src/TokenVault.sol +++ b/per_multicall/src/TokenVault.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; -import "./Errors.sol"; +import "./TokenVaultErrors.sol"; import "forge-std/console.sol"; import "forge-std/StdMath.sol"; import "./Structs.sol"; @@ -44,7 +44,7 @@ contract TokenVault is PERFeeReceiver { uint8 targetDecimals ) private pure returns (uint256) { if (price.price < 0 || price.expo > 0 || price.expo < -255) { - revert(); + revert InvalidPriceExponent(); } uint8 priceDecimals = uint8(uint32(-1 * price.expo)); diff --git a/per_multicall/src/TokenVaultErrors.sol b/per_multicall/src/TokenVaultErrors.sol new file mode 100644 index 00000000..7898adad --- /dev/null +++ b/per_multicall/src/TokenVaultErrors.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +error UncollateralizedVaultCreation(); + +error InvalidVaultUpdate(); + +error InvalidPriceExponent(); + +error InvalidLiquidation(); From 6d43b0b9bcc94f1898957e91ceae2ebfcd6c7fa1 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 12:16:13 +0100 Subject: [PATCH 15/41] Implement bid on opportunity endpoint --- auction-server/config.sample.yaml | 3 +- auction-server/src/api.rs | 19 +++- auction-server/src/api/marketplace.rs | 120 ++++++++++++++++------ auction-server/src/api/rest.rs | 8 +- auction-server/src/auction.rs | 25 +++-- auction-server/src/config.rs | 5 +- auction-server/src/liquidation_adapter.rs | 58 ++++++++--- 7 files changed, 175 insertions(+), 63 deletions(-) diff --git a/auction-server/config.sample.yaml b/auction-server/config.sample.yaml index 911841fe..a065f683 100644 --- a/auction-server/config.sample.yaml +++ b/auction-server/config.sample.yaml @@ -1,5 +1,6 @@ chains: development: geth_rpc_addr: http://localhost:8545 - contract_addr: 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 + per_contract: 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 + adapter_contract: 0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e legacy_tx: false diff --git a/auction-server/src/api.rs b/auction-server/src/api.rs index cd1d314e..f7a0f36b 100644 --- a/auction-server/src/api.rs +++ b/auction-server/src/api.rs @@ -47,6 +47,7 @@ use { LocalWallet, Signer, }, + types::Bytes, }, futures::future::join_all, std::{ @@ -58,6 +59,7 @@ use { }, Arc, }, + time::Duration, }, tower_http::cors::CorsLayer, utoipa::{ @@ -90,6 +92,8 @@ pub enum RestError { BadParameters(String), /// The chain id is not supported InvalidChainId, + /// The simulation failed + SimulationError { result: Bytes, reason: String }, /// The order was not found OpportunityNotFound, /// The server cannot currently communicate with the blockchain, so is not able to verify @@ -108,6 +112,11 @@ impl IntoResponse for RestError { RestError::InvalidChainId => { (StatusCode::BAD_REQUEST, "The chain id is not supported").into_response() } + RestError::SimulationError { result, reason } => ( + StatusCode::BAD_REQUEST, + format!("Simulation failed: {} ({})", result, reason), + ) + .into_response(), RestError::OpportunityNotFound => ( StatusCode::NOT_FOUND, "Order with the specified id was not found", @@ -141,6 +150,7 @@ pub async fn start_server(run_options: RunOptions) -> Result<()> { paths( rest::bid, marketplace::submit_opportunity, + marketplace::bid_opportunity, marketplace::fetch_opportunities, ), components( @@ -165,8 +175,8 @@ pub async fn start_server(run_options: RunOptions) -> Result<()> { let chain_store: Result> = join_all(config.chains.iter().map( |(chain_id, chain_config)| async move { - let provider = - Provider::::try_from(chain_config.geth_rpc_addr.clone()).map_err(|err| { + let mut provider = Provider::::try_from(chain_config.geth_rpc_addr.clone()) + .map_err(|err| { anyhow!( "Failed to connect to chain({chain_id}) at {rpc_addr}: {:?}", err, @@ -174,6 +184,7 @@ pub async fn start_server(run_options: RunOptions) -> Result<()> { rpc_addr = chain_config.geth_rpc_addr ) })?; + provider.set_interval(Duration::from_secs(1)); let id = provider.get_chainid().await?.as_u64(); Ok(( chain_id.clone(), @@ -212,6 +223,10 @@ pub async fn start_server(run_options: RunOptions) -> Result<()> { "/liquidation/fetch_opportunities", get(marketplace::fetch_opportunities), ) + .route( + "/liquidation/bid_opportunity", + post(marketplace::bid_opportunity), + ) .layer(CorsLayer::permissive()) .with_state(server_store); diff --git a/auction-server/src/api/marketplace.rs b/auction-server/src/api/marketplace.rs index 12a1d6c4..d4075961 100644 --- a/auction-server/src/api/marketplace.rs +++ b/auction-server/src/api/marketplace.rs @@ -4,7 +4,10 @@ use { rest::handle_bid, RestError, }, - liquidation_adapter::make_liquidator_calldata, + liquidation_adapter::{ + make_liquidator_calldata, + parse_revert_error, + }, state::Store, }, axum::{ @@ -23,7 +26,10 @@ use { Deserialize, Serialize, }, - std::sync::Arc, + std::{ + str::FromStr, + sync::Arc, + }, utoipa::ToSchema, uuid::Uuid, }; @@ -62,6 +68,17 @@ pub struct LiquidationOpportunity { receipt_tokens: Vec, } +/// A submitted liquidation opportunity ready to be executed. +/// If a searcher signs the opportunity and have approved enough tokens to liquidation adapter, by calling this contract with the given calldata and structures, they will receive the tokens specified in the receipt_tokens field, and will send the tokens specified in the repay_tokens field. +#[derive(Serialize, Deserialize, ToSchema, Clone)] +pub struct LiquidationOpportunityWithId { + /// The opportunity unique id + opportunity_id: Uuid, + /// opportunity data + #[serde(flatten)] + opportunity: LiquidationOpportunity, +} + impl From<(Address, U256)> for TokenQty { fn from(token: (Address, U256)) -> Self { TokenQty { @@ -89,7 +106,7 @@ fn parse_tokens(tokens: Vec) -> Result, RestError /// /// The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database and will be available for bidding. #[utoipa::path(post, path = "/liquidation/submit_opportunity", request_body = LiquidationOpportunity, responses( - (status = 200, description = "Opportunity was stored succesfuly", body = String), + (status = 200, description = "Opportunity was stored succesfuly with the returned uuid", body = String), (status = 400, response=RestError) ),)] pub async fn submit_opportunity( @@ -106,10 +123,11 @@ pub async fn submit_opportunity( //TODO: Verify if the call actually works + let id = Uuid::new_v4(); store.liquidation_store.opportunities.write().await.insert( opportunity.permission_key.clone(), crate::state::VerifiedLiquidationOpportunity { - id: Uuid::new_v4(), + id, chain_id: opportunity.chain_id.clone(), permission_key: opportunity.permission_key, contract: opportunity.contract, @@ -121,7 +139,7 @@ pub async fn submit_opportunity( }, ); - Ok("OK".to_string()) + Ok(id.to_string()) } /// Fetch all liquidation opportunities ready to be exectued. @@ -131,30 +149,33 @@ pub async fn submit_opportunity( ),)] pub async fn fetch_opportunities( State(store): State>, -) -> Result>, RestError> { - let opportunities: Vec = store +) -> Result>, RestError> { + let opportunities: Vec = store .liquidation_store .opportunities .read() .await .values() .cloned() - .map(|opportunity| LiquidationOpportunity { - permission_key: opportunity.permission_key, - chain_id: opportunity.chain_id, - contract: opportunity.contract, - calldata: opportunity.calldata, - value: opportunity.value.to_string(), - repay_tokens: opportunity - .repay_tokens - .into_iter() - .map(TokenQty::from) - .collect(), - receipt_tokens: opportunity - .receipt_tokens - .into_iter() - .map(TokenQty::from) - .collect(), + .map(|opportunity| LiquidationOpportunityWithId { + opportunity_id: opportunity.id, + opportunity: LiquidationOpportunity { + permission_key: opportunity.permission_key, + chain_id: opportunity.chain_id, + contract: opportunity.contract, + calldata: opportunity.calldata, + value: opportunity.value.to_string(), + repay_tokens: opportunity + .repay_tokens + .into_iter() + .map(TokenQty::from) + .collect(), + receipt_tokens: opportunity + .receipt_tokens + .into_iter() + .map(TokenQty::from) + .collect(), + }, }) .collect(); @@ -180,8 +201,8 @@ pub struct OpportunityBid { liquidator: Address, #[schema( example = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12" - ,value_type=String)] - signature: Signature, + )] + signature: String, } #[derive(Clone, Copy)] @@ -193,8 +214,13 @@ pub struct VerifiedOpportunityBid { pub signature: Signature, } +/// Bid on liquidation opportunity +#[utoipa::path(post, path = "/liquidation/bid_opportunity", request_body=OpportunityBid, responses( + (status = 200, description = "Bid Result", body = String), + (status = 400, response=RestError) +),)] pub async fn bid_opportunity( - store: Arc, + State(store): State>, Json(opportunity_bid): Json, ) -> Result { let opportunities = store.liquidation_store.opportunities.read().await; @@ -208,31 +234,59 @@ pub async fn bid_opportunity( "Invalid opportunity_id".to_string(), )); } + + let chain_store = store + .chains + .get(&liquidation.chain_id) + .ok_or(RestError::InvalidChainId)?; + let bid_amount = U256::from_dec_str(opportunity_bid.bid_amount.as_str()) .map_err(|_| RestError::BadParameters("Invalid bid_amount".to_string()))?; let valid_until = U256::from_dec_str(opportunity_bid.valid_until.as_str()) .map_err(|_| RestError::BadParameters("Invalid valid_until".to_string()))?; - + let signature = Signature::from_str(opportunity_bid.signature.as_str()) + .map_err(|_| RestError::BadParameters("Invalid signature".to_string()))?; let verified_liquidation_bid = VerifiedOpportunityBid { opportunity_id: opportunity_bid.opportunity_id, bid_amount, valid_until, liquidator: opportunity_bid.liquidator, - signature: opportunity_bid.signature, + signature, }; - let per_calldata = make_liquidator_calldata(liquidation.clone(), verified_liquidation_bid) - .map_err(|e| RestError::BadParameters(e.to_string()))?; - - handle_bid( + let per_calldata = make_liquidator_calldata( + liquidation.clone(), + verified_liquidation_bid, + chain_store.provider.clone(), + chain_store.config.adapter_contract, + ) + .await + .map_err(|e| RestError::BadParameters(e.to_string()))?; + match handle_bid( store.clone(), crate::api::rest::ParsedBid { permission_key: liquidation.permission_key.clone(), chain_id: liquidation.chain_id.clone(), - contract: liquidation.contract, + contract: chain_store.config.adapter_contract, calldata: per_calldata, bid_amount: verified_liquidation_bid.bid_amount, }, ) .await + { + Ok(_) => Ok("OK".to_string()), + Err(e) => match e { + RestError::SimulationError { result, reason } => { + let parsed = parse_revert_error(result.clone()); + match parsed { + Some(decoded) => Err(RestError::BadParameters(decoded)), + None => { + tracing::info!("Could not parse revert reason: {}", reason); + Err(RestError::SimulationError { result, reason }) + } + } + } + _ => Err(e), + }, + } } diff --git a/auction-server/src/api/rest.rs b/auction-server/src/api/rest.rs index 4bfdc92c..f093418e 100644 --- a/auction-server/src/api/rest.rs +++ b/auction-server/src/api/rest.rs @@ -84,10 +84,10 @@ pub async fn handle_bid(store: Arc, bid: ParsedBid) -> Result { diff --git a/auction-server/src/auction.rs b/auction-server/src/auction.rs index efe9a243..ab7f44de 100644 --- a/auction-server/src/auction.rs +++ b/auction-server/src/auction.rs @@ -77,7 +77,7 @@ pub async fn simulate_bids( bids: Vec, ) -> Result, ContractError>> { let client = Arc::new(provider); - let per_contract = PERContract::new(chain_config.contract_addr, client); + let per_contract = PERContract::new(chain_config.per_contract, client); let call = per_contract .multicall(permission, contracts, calldata, bids) .from(per_operator); @@ -126,17 +126,28 @@ pub async fn submit_bids( transformer, )); - let per_contract = SignablePERContract::new(chain_config.contract_addr, client); + let per_contract = SignablePERContract::new(chain_config.per_contract, client); let call = per_contract.multicall(permission, contracts, calldata, bids); - let send_call = call.send().await.map_err(SubmissionError::ContractError)?; - send_call.await.map_err(SubmissionError::ProviderError) + let mut gas_estimate = call + .estimate_gas() + .await + .map_err(SubmissionError::ContractError)?; + let gas_multiplier = U256::from(2); //TODO: smarter gas estimation + gas_estimate = gas_estimate * gas_multiplier; + let call_with_gas = call.gas(gas_estimate); + let send_call = call_with_gas + .send() + .await + .map_err(SubmissionError::ContractError)?; + let res = send_call.await.map_err(SubmissionError::ProviderError); + res } pub async fn run_submission_loop(store: Arc) { tracing::info!("Starting transaction submitter..."); while !SHOULD_EXIT.load(Ordering::Acquire) { for (chain_id, chain_store) in &store.chains { - let permission_bids = chain_store.bids.read().await; + let permission_bids = chain_store.bids.read().await.clone(); // release lock asap tracing::info!( "Chain: {chain_id} Auctions to process {auction_len}", chain_id = chain_id, @@ -147,7 +158,7 @@ pub async fn run_submission_loop(store: Arc) { let thread_store = store.clone(); let chain_id = chain_id.clone(); let permission_key = permission_key.clone(); - tokio::spawn(async move { + { cloned_bids.sort_by(|a, b| b.bid.cmp(&a.bid)); // TODO: simulate all bids together and keep the successful ones @@ -196,7 +207,7 @@ pub async fn run_submission_loop(store: Arc) { tracing::error!("Chain not found: {}", chain_id); } } - }); + } } } tokio::time::sleep(Duration::from_secs(10)).await; // this should be replaced by a subscription to the chain and trigger on new blocks diff --git a/auction-server/src/config.rs b/auction-server/src/config.rs index aa966c9e..e5ed0723 100644 --- a/auction-server/src/config.rs +++ b/auction-server/src/config.rs @@ -78,7 +78,10 @@ pub struct EthereumConfig { pub geth_rpc_addr: String, /// Address of the PER contract to interact with. - pub contract_addr: Address, + pub per_contract: Address, + + /// Address of the adapter contract to interact with. + pub adapter_contract: Address, /// Use the legacy transaction format (for networks without EIP 1559) #[serde(default)] diff --git a/auction-server/src/liquidation_adapter.rs b/auction-server/src/liquidation_adapter.rs index c6cf4ccf..b142ee3a 100644 --- a/auction-server/src/liquidation_adapter.rs +++ b/auction-server/src/liquidation_adapter.rs @@ -8,15 +8,19 @@ use { Result, }, ethers::{ - abi::{ - AbiEncode, - Tokenizable, + abi::Tokenizable, + contract::{ + abigen, + ContractRevert, }, - contract::abigen, core::{ abi, utils::keccak256, }, + providers::{ + Http, + Provider, + }, types::{ Address, Bytes, @@ -26,12 +30,16 @@ use { U256, }, }, + std::sync::Arc, }; abigen!( LiquidationAdapter, "../per_multicall/out/LiquidationAdapter.sol/LiquidationAdapter.json" ); +abigen!(ERC20, "../per_multicall/out/ERC20.sol/ERC20.json"); +abigen!(WETH9, "../per_multicall/out/WETH9.sol/WETH9.json"); + impl From<(Address, U256)> for TokenQty { fn from(token: (Address, U256)) -> Self { TokenQty { @@ -41,21 +49,21 @@ impl From<(Address, U256)> for TokenQty { } } - pub fn verify_signature(params: liquidation_adapter::LiquidationCallParams) -> Result<()> { // this should reflect the verifyCalldata function in the LiquidationAdapter contract - let data = abi::encode(&[ + let data = Bytes::from(abi::encode(&[ params.repay_tokens.into_token(), params.expected_receipt_tokens.into_token(), params.contract_address.into_token(), params.data.into_token(), params.value.into_token(), params.bid.into_token(), - ]); - let nonce = params.valid_until; + ])); + // encode packed does not work correctly for U256 so we need to convert it to bytes first + let nonce_bytes = Bytes::from(<[u8; 32]>::from(params.valid_until)); let digest = H256(keccak256(abi::encode_packed(&[ data.into_token(), - nonce.into_token(), + nonce_bytes.into_token(), ])?)); let signature = Signature::try_from(params.signature_liquidator.to_vec().as_slice()) .map_err(|_x| anyhow!("Error reading signature"))?; @@ -65,15 +73,28 @@ pub fn verify_signature(params: liquidation_adapter::LiquidationCallParams) -> R let is_matched = signer == params.liquidator; is_matched.then_some(()).ok_or_else(|| { anyhow!(format!( - "Invalid signature. Expected: {}, Got: {}", + "Invalid signature. Expected signer: {}, Got: {}", params.liquidator, signer )) }) } -pub fn make_liquidator_calldata( +pub fn parse_revert_error(revert: Bytes) -> Option { + let apdapter_decoded = + liquidation_adapter::LiquidationAdapterErrors::decode_with_selector(&revert) + .map(|err| format!("Liquidation Adapter Contract Revert Error: {:#?}", err)); + let erc20_decoded = erc20::ERC20Errors::decode_with_selector(&revert).map(|err| { + tracing::info!("ERC20 Contract Revert Error: {:#?}", err); + format!("ERC20 Contract Revert Error: {:#?}", err) + }); + apdapter_decoded.or(erc20_decoded) +} + +pub async fn make_liquidator_calldata( opportunity: VerifiedLiquidationOpportunity, bid: VerifiedOpportunityBid, + provider: Provider, + adapter_contract: Address, ) -> Result { let params = liquidation_adapter::LiquidationCallParams { repay_tokens: opportunity @@ -94,8 +115,15 @@ pub fn make_liquidator_calldata( bid: bid.bid_amount, signature_liquidator: bid.signature.to_vec().into(), }; - match verify_signature(params.clone()) { - Ok(_) => Ok(params.encode().into()), - Err(e) => Err(e), - } + let client = Arc::new(provider); + verify_signature(params.clone())?; + + let calldata = LiquidationAdapter::new(adapter_contract, client.clone()) + .call_liquidation(params) + .calldata() + .ok_or(anyhow!( + "Failed to generate calldata for liquidation adapter" + ))?; + + Ok(calldata) } From c8431267b4cbb8af7c970f16af41e60e5f8dd404 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 12:30:44 +0100 Subject: [PATCH 16/41] Fix on searcher and vault monitor vault monitor needs to include value and WETH if necessary searcher uses the new endpoint for bidding --- ...on_TokenVault.py => beacon_token_vault.py} | 50 +++++-- beacon/searcher/searcherA.py | 85 ------------ beacon/searcher/searcher_utils.py | 27 +++- beacon/searcher/simple_searcher.py | 122 ++++++++++++++++++ beacon/surface_opportunities.py | 45 ------- beacon/utils/endpoints.py | 7 +- beacon/utils/pyth_prices.py | 2 +- beacon/utils/types_liquidation_adapter.py | 19 +-- 8 files changed, 194 insertions(+), 163 deletions(-) rename beacon/protocols/{beacon_TokenVault.py => beacon_token_vault.py} (86%) delete mode 100644 beacon/searcher/searcherA.py create mode 100644 beacon/searcher/simple_searcher.py delete mode 100644 beacon/surface_opportunities.py diff --git a/beacon/protocols/beacon_TokenVault.py b/beacon/protocols/beacon_token_vault.py similarity index 86% rename from beacon/protocols/beacon_TokenVault.py rename to beacon/protocols/beacon_token_vault.py index 70c0eb27..5e5c3a41 100644 --- a/beacon/protocols/beacon_TokenVault.py +++ b/beacon/protocols/beacon_token_vault.py @@ -39,10 +39,12 @@ def get_vault_abi(): class VaultMonitor: - def __init__(self, rpc_url: str, contract_address: str): + def __init__(self, rpc_url: str, contract_address: str, weth_address: str): self.rpc_url = rpc_url self.contract_address = contract_address + self.weth_address = weth_address self.w3 = web3.AsyncWeb3(web3.AsyncHTTPProvider(rpc_url)) + self.token_vault = self.w3.eth.contract( address=contract_address, abi=get_vault_abi() ) @@ -73,10 +75,7 @@ async def get_accounts(self) -> list[ProtocolAccount]: vault = await self.token_vault.functions.getVault(account_number).call() vault_dict = dict(zip(vault_struct, vault)) - if ( - int(vault_dict["tokenCollateral"], 16) == 0 - and int(vault_dict["tokenDebt"], 16) == 0 - ): + if int(vault_dict["tokenCollateral"], 16) == 0: # vault is not created yet done = True else: account: ProtocolAccount = { @@ -111,10 +110,9 @@ def create_liquidation_opp( """ price_updates = [base64.b64decode(update["vaa"]) for update in prices] - w3 = web3.Web3() - abi = get_vault_abi() - token_vault = w3.eth.contract(address=self.contract_address, abi=abi) - calldata = token_vault.encodeABI( + for update in prices: + print(update["feed_id"], update["price"]["publish_time"]) + calldata = self.token_vault.encodeABI( fn_name="liquidateWithPriceUpdate", args=[account["account_number"], price_updates], ) @@ -125,6 +123,20 @@ def create_liquidation_opp( ["address", "bytes"], [self.contract_address, permission_payload] ).hex() ) + call_value = len(price_updates) + + if call_value > 0 and account["token_address_collateral"] == self.weth_address: + repay_tokens = [ + ( + account["token_address_debt"], + str(account["amount_debt"] + call_value), + ) + ] + else: + repay_tokens = [ + (account["token_address_debt"], str(account["amount_debt"])), + (self.weth_address, str(call_value)), + ] opp: LiquidationOpportunity = { "chain_id": "development", @@ -132,10 +144,8 @@ def create_liquidation_opp( "calldata": calldata, "permission_key": permission, "account": str(account["account_number"]), - "value": str(len(price_updates)), - "repay_tokens": [ - (account["token_address_debt"], str(account["amount_debt"])) - ], + "value": str(call_value), + "repay_tokens": repay_tokens, "receipt_tokens": [ (account["token_address_collateral"], str(account["amount_collateral"])) @@ -164,6 +174,9 @@ async def get_liquidation_opportunities(self) -> (list[LiquidationOpportunity]): liquidatable = [] accounts = await self.get_accounts() for account in accounts: + # vault is already liquidated + if account["amount_collateral"] == 0 and account["amount_debt"] == 0: + continue # TODO: optimize this to only query for the price feeds that are needed and only query once ( price_collateral, @@ -187,6 +200,7 @@ async def get_liquidation_opportunities(self) -> (list[LiquidationOpportunity]): ) value_debt = int(price_debt["price"] ["price"]) * account["amount_debt"] + print(account["account_number"], value_collateral / value_debt) if ( value_debt * int(account["min_health_ratio"]) > value_collateral * 10**18 @@ -213,6 +227,13 @@ async def main(): dest="vault_contract", help="Token vault contract address", ) + parser.add_argument( + "--weth-contract", + type=str, + required=True, + dest="weth_contract", + help="WETH contract address", + ) group = parser.add_mutually_exclusive_group(required=True) group.add_argument( "--dry-run", @@ -230,7 +251,8 @@ async def main(): logging.basicConfig(level=logging.INFO) logging.getLogger("httpx").propagate = False - monitor = VaultMonitor(args.rpc_url, args.vault_contract) + monitor = VaultMonitor( + args.rpc_url, args.vault_contract, args.weth_contract) while True: opportunities = await monitor.get_liquidation_opportunities() diff --git a/beacon/searcher/searcherA.py b/beacon/searcher/searcherA.py deleted file mode 100644 index 8070739d..00000000 --- a/beacon/searcher/searcherA.py +++ /dev/null @@ -1,85 +0,0 @@ -import web3 -from web3.auto import w3 -from eth_account import Account -from eth_account.signers.local import LocalAccount -from eth_abi import encode -import httpx -import asyncio - -from beacon.utils.types_liquidation_adapter import * -from beacon.utils.endpoints import * -from beacon.searcher.searcher_utils import * - -TOKEN_VAULT_ADDRESS = "0x72A22FfcAfa6684d4EE449620270ac05afE963d0" - -BID = 10 -VALID_UNTIL = 1_000_000_000_000 - - -def create_liquidation_intent( - opp: LiquidationOpportunity, - sk_liquidator: str, - valid_until: int, - bid: int -) -> LiquidationAdapterIntent: - repay_tokens = [(opp['repay_tokens'][0]['contract'], - int(opp['repay_tokens'][0]['amount']))] - receipt_tokens = [(opp['receipt_tokens'][0]['contract'], - int(opp['receipt_tokens'][0]['amount']))] - - account: LocalAccount = Account.from_key(sk_liquidator) - liquidator = account.address - liq_calldata = bytes.fromhex(opp['calldata'].replace('0x', '')) - - signature_liquidator = construct_signature_liquidator( - repay_tokens, receipt_tokens, opp['contract'], liq_calldata, bid, valid_until, sk_liquidator) - - liquidation_adapter_calldata: LiquidationAdapterCalldata = { - "repay_tokens": repay_tokens, - "expected_receipt_tokens": receipt_tokens, - "liquidator": liquidator, - "contract": opp['contract'], - "data": liq_calldata, - "valid_until": valid_until, - "bid": bid, - "signature_liquidator": bytes(signature_liquidator.signature) - } - calldata = LIQUIDATION_ADAPTER_FN_SIGNATURE + \ - encode([LIQUIDATION_ADAPTER_CALLDATA_TYPES], [ - tuple(liquidation_adapter_calldata.values())]).hex() - - intent: LiquidationAdapterIntent = { - "bid": str(bid), - "calldata": calldata, - "chain_id": opp["chain_id"], - "contract": LIQUIDATION_ADAPTER_ADDRESS, - "permission_key": opp['permission_key'] - } - - return intent - - -async def main(): - CLIENT = httpx.AsyncClient() - - params = {"chain_id": "development", "contract": TOKEN_VAULT_ADDRESS} - - liquidatable = (await CLIENT.get(BEACON_SERVER_ENDPOINT_GETOPPS, params=params)).json() - - # this is hardcoded to the searcher A SK - sk_liquidator = "0x5b1efe5da513271c0d30cde7a2ad1d29456d68abd592efdaa7d2302e913b783f" - intent = create_liquidation_intent( - liquidatable[0], sk_liquidator, VALID_UNTIL, BID) - - resp = await CLIENT.post( - AUCTION_SERVER_ENDPOINT, - json=intent - ) - - print(resp.text) - - import pdb - pdb.set_trace() - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/beacon/searcher/searcher_utils.py b/beacon/searcher/searcher_utils.py index b25caafc..8e94c76e 100644 --- a/beacon/searcher/searcher_utils.py +++ b/beacon/searcher/searcher_utils.py @@ -1,6 +1,12 @@ import web3 from web3.auto import w3 from eth_abi import encode +from typing import TypedDict + + +class UserLiquidationParams(TypedDict): + bid: int + valid_until: int def construct_signature_liquidator( @@ -8,14 +14,31 @@ def construct_signature_liquidator( receipt_tokens: list[(str, int)], address: str, liq_calldata: bytes, + value: int, bid: int, valid_until: int, secret_key: str ): + """ + Constructs a signature for a liquidator's transaction to submit to the LiquidationAdapter contract. + + Args: + repay_tokens: A list of tuples (token address, amount) representing the tokens to repay. + receipt_tokens: A list of tuples (token address, amount) representing the tokens to receive. + address: The address of the LiquidationAdapter contract. + liq_calldata: The calldata for the liquidation method call. + value: The value for the liquidation method call. + bid: The amount of native token to bid on this opportunity. + valid_until: The timestamp at which the transaction will expire. + secret_key: A 0x-prefixed hex string representing the liquidator's private key. + Returns: + An web3 ECDSASignature object, representing the liquidator's signature. + """ + digest = encode( ['(address,uint256)[]', '(address,uint256)[]', - 'address', 'bytes', 'uint256'], - [repay_tokens, receipt_tokens, address, liq_calldata, bid] + 'address', 'bytes', 'uint256', 'uint256'], + [repay_tokens, receipt_tokens, address, liq_calldata, value, bid] ) msg_data = web3.Web3.solidity_keccak( ['bytes', 'uint256'], [digest, valid_until]) diff --git a/beacon/searcher/simple_searcher.py b/beacon/searcher/simple_searcher.py new file mode 100644 index 00000000..0c2b95f5 --- /dev/null +++ b/beacon/searcher/simple_searcher.py @@ -0,0 +1,122 @@ +from eth_account import Account +from eth_account.signers.local import LocalAccount +from eth_abi import encode +import httpx +import logging +import asyncio +import argparse + +from beacon.utils.types_liquidation_adapter import * +from beacon.utils.endpoints import BEACON_SERVER_ENDPOINT_GETOPPS, BEACON_SERVER_ENDPOINT_BID +from beacon.searcher.searcher_utils import UserLiquidationParams, construct_signature_liquidator + +BID = 10 +VALID_UNTIL = 1_000_000_000_000 + + +def assess_liquidation_opportunity( + opp: LiquidationOpportunity +) -> UserLiquidationParams | None: + user_liquidation_params: UserLiquidationParams = { + "bid": BID, + "valid_until": VALID_UNTIL + } + return user_liquidation_params + + +class OpportunityBid(TypedDict): + opportunity_id: str + permission_key: str + bid_amount: str + valid_until: str + liquidator: str + signature: str + + +def create_liquidation_transaction( + opp: LiquidationOpportunity, + sk_liquidator: str, + valid_until: int, + bid: int +) -> OpportunityBid: + repay_tokens = [(opp['contract'], int(opp['amount'])) + for opp in opp['repay_tokens']] + receipt_tokens = [(opp['contract'], int(opp['amount'])) + for opp in opp['receipt_tokens']] + + account: LocalAccount = Account.from_key(sk_liquidator) + liquidator = account.address + liq_calldata = bytes.fromhex(opp['calldata'].replace('0x', '')) + + signature_liquidator = construct_signature_liquidator( + repay_tokens, receipt_tokens, opp['contract'], liq_calldata, int(opp['value']), bid, valid_until, sk_liquidator) + + liquidation_adapter_calldata: LiquidationAdapterCalldata = { + "repay_tokens": repay_tokens, + "expected_receipt_tokens": receipt_tokens, + "liquidator": liquidator, + "contract": opp['contract'], + "data": liq_calldata, + "valid_until": valid_until, + "bid": bid, + "signature_liquidator": bytes(signature_liquidator.signature) + } + + json_body: OpportunityBid = { + "chain_id": opp['chain_id'], + "opportunity_id": opp['opportunity_id'], + "permission_key": opp['permission_key'], + "bid_amount": str(bid), + "valid_until": str(valid_until), + "liquidator": liquidator, + "signature": bytes(signature_liquidator.signature).hex() + } + + return json_body + + +async def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--private-key", + type=str, + required=True, + help="Private key of the searcher for signing calldata", + ) + parser.add_argument( + "--chain-id", + type=str, + required=True, + help="Chain ID of the network to monitor for liquidation opportunities", + ) + args = parser.parse_args() + + logging.basicConfig(level=logging.INFO) + logging.getLogger("httpx").propagate = False + + params = {"chain_id": args.chain_id} + sk_liquidator = args.private_key + client = httpx.AsyncClient() + while True: + accounts_liquidatable = (await client.get(BEACON_SERVER_ENDPOINT_GETOPPS, params=params)).json() + + for liquidation_opp in accounts_liquidatable: + user_liquidation_params = assess_liquidation_opportunity( + liquidation_opp) + + if user_liquidation_params is not None: + bid, valid_until = user_liquidation_params["bid"], user_liquidation_params["valid_until"] + + tx = create_liquidation_transaction( + liquidation_opp, sk_liquidator, valid_until, bid) + + resp = await client.post( + BEACON_SERVER_ENDPOINT_BID, + json=tx + ) + + print(resp.text) + await asyncio.sleep(5) + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/beacon/surface_opportunities.py b/beacon/surface_opportunities.py deleted file mode 100644 index d891f031..00000000 --- a/beacon/surface_opportunities.py +++ /dev/null @@ -1,45 +0,0 @@ -import httpx -import asyncio - -from beacon.protocols import beacon_TokenVault -from beacon.utils.pyth_prices import * -from beacon.utils.endpoints import * - -# TODO: turn on authorization in the surface post requests -OPERATOR_API_KEY = "password" -PROTOCOLS = [beacon_TokenVault] - - -async def main(): - # get prices - pyth_price_feed_ids = await get_price_feed_ids() - pyth_prices_latest = [] - i = 0 - cntr = 100 - while len(pyth_price_feed_ids[i:i + cntr]) > 0: - pyth_prices_latest += await get_pyth_prices_latest(pyth_price_feed_ids[i:i + cntr]) - i += cntr - pyth_prices_latest = dict(pyth_prices_latest) - - liquidatable = [] - - for protocol in PROTOCOLS: - accounts = await protocol.get_accounts() - - liquidatable_protocol = protocol.get_liquidation_opportunities( - accounts, pyth_prices_latest) - - liquidatable += liquidatable_protocol - - CLIENT = httpx.AsyncClient() - - for item in liquidatable: - resp = await CLIENT.post( - f"{BEACON_SERVER_ENDPOINT_SURFACE}", - json=item - ) - print(f"Response PER post: {resp.text}") - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/beacon/utils/endpoints.py b/beacon/utils/endpoints.py index bd969fd6..c21f3974 100644 --- a/beacon/utils/endpoints.py +++ b/beacon/utils/endpoints.py @@ -1,7 +1,6 @@ BEACON_SERVER_ENDPOINT = "http://localhost:9000" AUCTION_SERVER_ENDPOINT = f"http://localhost:9000/bid" -BEACON_SERVER_ENDPOINT_SURFACE = f"{ - BEACON_SERVER_ENDPOINT}/liquidation/submit_opportunity" -BEACON_SERVER_ENDPOINT_GETOPPS = f"{ - BEACON_SERVER_ENDPOINT}/liquidation/fetch_opportunities" +BEACON_SERVER_ENDPOINT_SURFACE = f"{BEACON_SERVER_ENDPOINT}/liquidation/submit_opportunity" +BEACON_SERVER_ENDPOINT_GETOPPS = f"{BEACON_SERVER_ENDPOINT}/liquidation/fetch_opportunities" +BEACON_SERVER_ENDPOINT_BID = f"{BEACON_SERVER_ENDPOINT}/liquidation/bid_opportunity" diff --git a/beacon/utils/pyth_prices.py b/beacon/utils/pyth_prices.py index 7e7243e5..c159666f 100644 --- a/beacon/utils/pyth_prices.py +++ b/beacon/utils/pyth_prices.py @@ -14,7 +14,7 @@ class Price(TypedDict): class PriceFeed(TypedDict): - id: str + feed_id: str price: Price ema_price: Price vaa: str diff --git a/beacon/utils/types_liquidation_adapter.py b/beacon/utils/types_liquidation_adapter.py index 27cbd3d9..cfdbbbca 100644 --- a/beacon/utils/types_liquidation_adapter.py +++ b/beacon/utils/types_liquidation_adapter.py @@ -1,9 +1,4 @@ from typing import TypedDict -import web3 - -from beacon.utils.pyth_prices import PriceFeed - -LIQUIDATION_ADAPTER_ADDRESS = "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6" class TokenQty(TypedDict): @@ -12,24 +7,24 @@ class TokenQty(TypedDict): class LiquidationOpportunity(TypedDict): + # The unique id of the opportunity + opportunity_id: str + # The id of the chain where the opportunity was found chain_id: str # Address of the contract where the liquidation method is called contract: str # The calldata that needs to be passed in with the liquidation method call calldata: str + # The value that needs to be passed in with the liquidation method call + value: str + # The permission key necessary to call the liquidation method permission_key: str - account: str # A list of tokens that can be used to repay this account's debt. Each entry in the list is a tuple (token address, hex string of repay amount) repay_tokens: list[TokenQty] # A list of tokens that ought to be received by the liquidator in exchange for the repay tokens. Each entry in the list is a tuple (token address, hex string of receipt amount) receipt_tokens: list[TokenQty] -LIQUIDATION_ADAPTER_CALLDATA_TYPES = '((address,uint256)[],(address,uint256)[],address,address,bytes,uint256,uint256,bytes)' -LIQUIDATION_ADAPTER_FN_SIGNATURE = web3.Web3.solidity_keccak( - ["string"], [f"callLiquidation({LIQUIDATION_ADAPTER_CALLDATA_TYPES})"])[:4].hex() - - class LiquidationAdapterCalldata(TypedDict): repay_tokens: list[(str, int)] expected_receipt_tokens: list[(str, int)] @@ -41,7 +36,7 @@ class LiquidationAdapterCalldata(TypedDict): signature_liquidator: bytes -class LiquidationAdapterIntent(TypedDict): +class LiquidationAdapterTransaction(TypedDict): bid: str calldata: str chain_id: str From f4ff2942c5b33656ced9951aee1d5578c5a948eb Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 16:15:26 +0100 Subject: [PATCH 17/41] Setup poetry and replace autopep8 with black --- .pre-commit-config.yaml | 18 +- beacon/protocols/beacon_template.py | 92 - beacon/utils/endpoints.py | 6 - per_sdk/poetry.lock | 1839 +++++++++++++++++ .../protocols/beacon_token_vault.py | 31 +- per_sdk/pyproject.toml | 62 + .../searcher/searcher_template.py | 0 .../searcher/searcher_utils.py | 25 +- .../searcher/simple_searcher.py | 97 +- per_sdk/utils/endpoints.py | 10 + {beacon => per_sdk}/utils/pyth_prices.py | 36 +- .../utils/types_liquidation_adapter.py | 0 12 files changed, 2022 insertions(+), 194 deletions(-) delete mode 100644 beacon/protocols/beacon_template.py delete mode 100644 beacon/utils/endpoints.py create mode 100644 per_sdk/poetry.lock rename {beacon => per_sdk}/protocols/beacon_token_vault.py (93%) create mode 100644 per_sdk/pyproject.toml rename {beacon => per_sdk}/searcher/searcher_template.py (100%) rename {beacon => per_sdk}/searcher/searcher_utils.py (78%) rename {beacon => per_sdk}/searcher/simple_searcher.py (54%) create mode 100644 per_sdk/utils/endpoints.py rename {beacon => per_sdk}/utils/pyth_prices.py (88%) rename {beacon => per_sdk}/utils/types_liquidation_adapter.py (100%) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 946beb7d..b3535ca8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,7 +35,19 @@ repos: files: vault-simulator # for python files - - repo: https://github.com/hhatto/autopep8 - rev: "v2.0.4" + - repo: local hooks: - - id: autopep8 + - id: isort + name: isort + entry: poetry -C per_sdk run isort --profile=black per_sdk + language: system + - id: black + name: black + entry: poetry -C per_sdk run black per_sdk + pass_filenames: false + language: system + - id: pyflakes + name: pyflakes + entry: poetry -C per_sdk run pyflakes per_sdk + pass_filenames: false + language: system diff --git a/beacon/protocols/beacon_template.py b/beacon/protocols/beacon_template.py deleted file mode 100644 index 8ceacc25..00000000 --- a/beacon/protocols/beacon_template.py +++ /dev/null @@ -1,92 +0,0 @@ -import web3 -from eth_abi import encode -import json -from typing import TypedDict - -from beacon.utils.pyth_prices import * -from beacon.utils.types_liquidation_adapter import * - -PROTOCOL_ADDRESS = "{INSERT}" -CHAIN_RPC_ENDPOINT = "http://localhost:8545" - -""" -The protocol should implement a class called LiquidationAccount. This will be the type of the objects in the list returned by get_accounts() and fed into get_liquidatable. -This class should contain all the relevant information about a vault/account on this protocol that is necessary for identifying whether it is eligible for liquidation and constructing a LiquidationOpportunity object. -""" - - -class LiquidationAccount(TypedDict): - # Keys of the TypedDict and their types - pass - - -""" -get_accounts() is the first method that the protocol should implement. It should take no arguments and return all the open accounts in the protocol in the form of a list of objects of type LiquidationAccount (defined above). Each LiquidationAccount object represents an account/vault in the protocol. -This function can be implemented in any way, but it should be able to return all the open accounts in the protocol. For some protocols, this may be easily doable by just querying on-chain state; however, most protocols will likely need to maintain or access an off-chain indexer to get the list of all open accounts. -""" - - -async def get_accounts() -> list[LiquidationAccount]: - # Fetch all vaults from on-chain state/indexer - # Filter to just active vaults - # Return list of LiquidationAccount - # TODO: complete - pass - - -""" -create_liquidation_opp is an optional helper function to construct a LiquidationOpportunity from a LiquidationAccount and a set of relevant Pyth PriceFeeds. -If you choose to implement this function, you can call it within get_liquidatable whenever you find a LiquidationAccount eligible for liquidation. -""" - - -def create_liquidation_opp( - account: LiquidationAccount, - prices: list[PriceFeed]) -> LiquidationOpportunity: - pass - - -""" -get_liquidatable(accounts, prices) is the second method that the protocol should implement. It should take two arguments: account--a list of LiquidationAccount (defined above) objects--and prices--a dictionary of Pyth prices. -accounts should be the list of all open accounts in the protocol (i.e. the output of get_accounts()). -prices should be a dictionary of Pyth prices, where the keys are Pyth feed IDs and the values are PriceFeed objects. prices can be retrieved from the provided price retrieval functions. -This function should return a list of type LiquidationOpportunity. -""" - - -def get_liquidatable(accounts: list[LiquidationAccount], - prices: dict[str, - PriceFeed]) -> (list[LiquidationOpportunity]): - # Iterate through accounts - # Determine if account is eligible for liquidation; if so, construct an object of type LiquidationOpportunity and add it to the list - # Return the list of type LiquidationOpportunity containing all the valid liquidation opportunities - pass - - -""" -The main loop below is a good mechanism to check if your implementations of the functions above are working properly. -""" - - -async def main(): - # get all accounts - accounts = await get_accounts() - - # get prices - pyth_price_feed_ids = await get_price_feed_ids() - pyth_prices_latest = [] - i = 0 - cntr = 100 - while len(pyth_price_feed_ids[i:i + cntr]) > 0: - pyth_prices_latest += await get_pyth_prices_latest(pyth_price_feed_ids[i:i + cntr]) - i += cntr - pyth_prices_latest = dict(pyth_prices_latest) - - # get liquidatable accounts - liquidatable = get_liquidatable( - accounts, pyth_prices_latest) - - print(liquidatable) - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/beacon/utils/endpoints.py b/beacon/utils/endpoints.py deleted file mode 100644 index c21f3974..00000000 --- a/beacon/utils/endpoints.py +++ /dev/null @@ -1,6 +0,0 @@ -BEACON_SERVER_ENDPOINT = "http://localhost:9000" -AUCTION_SERVER_ENDPOINT = f"http://localhost:9000/bid" - -BEACON_SERVER_ENDPOINT_SURFACE = f"{BEACON_SERVER_ENDPOINT}/liquidation/submit_opportunity" -BEACON_SERVER_ENDPOINT_GETOPPS = f"{BEACON_SERVER_ENDPOINT}/liquidation/fetch_opportunities" -BEACON_SERVER_ENDPOINT_BID = f"{BEACON_SERVER_ENDPOINT}/liquidation/bid_opportunity" diff --git a/per_sdk/poetry.lock b/per_sdk/poetry.lock new file mode 100644 index 00000000..15db4bdb --- /dev/null +++ b/per_sdk/poetry.lock @@ -0,0 +1,1839 @@ +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. + +[[package]] +name = "aiohttp" +version = "3.9.1" +description = "Async http client/server framework (asyncio)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiohttp-3.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e1f80197f8b0b846a8d5cf7b7ec6084493950d0882cc5537fb7b96a69e3c8590"}, + {file = "aiohttp-3.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c72444d17777865734aa1a4d167794c34b63e5883abb90356a0364a28904e6c0"}, + {file = "aiohttp-3.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9b05d5cbe9dafcdc733262c3a99ccf63d2f7ce02543620d2bd8db4d4f7a22f83"}, + {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c4fa235d534b3547184831c624c0b7c1e262cd1de847d95085ec94c16fddcd5"}, + {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:289ba9ae8e88d0ba16062ecf02dd730b34186ea3b1e7489046fc338bdc3361c4"}, + {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bff7e2811814fa2271be95ab6e84c9436d027a0e59665de60edf44e529a42c1f"}, + {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81b77f868814346662c96ab36b875d7814ebf82340d3284a31681085c051320f"}, + {file = "aiohttp-3.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b9c7426923bb7bd66d409da46c41e3fb40f5caf679da624439b9eba92043fa6"}, + {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8d44e7bf06b0c0a70a20f9100af9fcfd7f6d9d3913e37754c12d424179b4e48f"}, + {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22698f01ff5653fe66d16ffb7658f582a0ac084d7da1323e39fd9eab326a1f26"}, + {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ca7ca5abfbfe8d39e653870fbe8d7710be7a857f8a8386fc9de1aae2e02ce7e4"}, + {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8d7f98fde213f74561be1d6d3fa353656197f75d4edfbb3d94c9eb9b0fc47f5d"}, + {file = "aiohttp-3.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5216b6082c624b55cfe79af5d538e499cd5f5b976820eac31951fb4325974501"}, + {file = "aiohttp-3.9.1-cp310-cp310-win32.whl", hash = "sha256:0e7ba7ff228c0d9a2cd66194e90f2bca6e0abca810b786901a569c0de082f489"}, + {file = "aiohttp-3.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:c7e939f1ae428a86e4abbb9a7c4732bf4706048818dfd979e5e2839ce0159f23"}, + {file = "aiohttp-3.9.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:df9cf74b9bc03d586fc53ba470828d7b77ce51b0582d1d0b5b2fb673c0baa32d"}, + {file = "aiohttp-3.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ecca113f19d5e74048c001934045a2b9368d77b0b17691d905af18bd1c21275e"}, + {file = "aiohttp-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8cef8710fb849d97c533f259103f09bac167a008d7131d7b2b0e3a33269185c0"}, + {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bea94403a21eb94c93386d559bce297381609153e418a3ffc7d6bf772f59cc35"}, + {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91c742ca59045dce7ba76cab6e223e41d2c70d79e82c284a96411f8645e2afff"}, + {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6c93b7c2e52061f0925c3382d5cb8980e40f91c989563d3d32ca280069fd6a87"}, + {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee2527134f95e106cc1653e9ac78846f3a2ec1004cf20ef4e02038035a74544d"}, + {file = "aiohttp-3.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11ff168d752cb41e8492817e10fb4f85828f6a0142b9726a30c27c35a1835f01"}, + {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b8c3a67eb87394386847d188996920f33b01b32155f0a94f36ca0e0c635bf3e3"}, + {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c7b5d5d64e2a14e35a9240b33b89389e0035e6de8dbb7ffa50d10d8b65c57449"}, + {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:69985d50a2b6f709412d944ffb2e97d0be154ea90600b7a921f95a87d6f108a2"}, + {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:c9110c06eaaac7e1f5562caf481f18ccf8f6fdf4c3323feab28a93d34cc646bd"}, + {file = "aiohttp-3.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737e69d193dac7296365a6dcb73bbbf53bb760ab25a3727716bbd42022e8d7a"}, + {file = "aiohttp-3.9.1-cp311-cp311-win32.whl", hash = "sha256:4ee8caa925aebc1e64e98432d78ea8de67b2272252b0a931d2ac3bd876ad5544"}, + {file = "aiohttp-3.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:a34086c5cc285be878622e0a6ab897a986a6e8bf5b67ecb377015f06ed316587"}, + {file = "aiohttp-3.9.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f800164276eec54e0af5c99feb9494c295118fc10a11b997bbb1348ba1a52065"}, + {file = "aiohttp-3.9.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:500f1c59906cd142d452074f3811614be04819a38ae2b3239a48b82649c08821"}, + {file = "aiohttp-3.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0b0a6a36ed7e164c6df1e18ee47afbd1990ce47cb428739d6c99aaabfaf1b3af"}, + {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69da0f3ed3496808e8cbc5123a866c41c12c15baaaead96d256477edf168eb57"}, + {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:176df045597e674fa950bf5ae536be85699e04cea68fa3a616cf75e413737eb5"}, + {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b796b44111f0cab6bbf66214186e44734b5baab949cb5fb56154142a92989aeb"}, + {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f27fdaadce22f2ef950fc10dcdf8048407c3b42b73779e48a4e76b3c35bca26c"}, + {file = "aiohttp-3.9.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcb6532b9814ea7c5a6a3299747c49de30e84472fa72821b07f5a9818bce0f66"}, + {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:54631fb69a6e44b2ba522f7c22a6fb2667a02fd97d636048478db2fd8c4e98fe"}, + {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4b4c452d0190c5a820d3f5c0f3cd8a28ace48c54053e24da9d6041bf81113183"}, + {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:cae4c0c2ca800c793cae07ef3d40794625471040a87e1ba392039639ad61ab5b"}, + {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:565760d6812b8d78d416c3c7cfdf5362fbe0d0d25b82fed75d0d29e18d7fc30f"}, + {file = "aiohttp-3.9.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54311eb54f3a0c45efb9ed0d0a8f43d1bc6060d773f6973efd90037a51cd0a3f"}, + {file = "aiohttp-3.9.1-cp312-cp312-win32.whl", hash = "sha256:85c3e3c9cb1d480e0b9a64c658cd66b3cfb8e721636ab8b0e746e2d79a7a9eed"}, + {file = "aiohttp-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:11cb254e397a82efb1805d12561e80124928e04e9c4483587ce7390b3866d213"}, + {file = "aiohttp-3.9.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8a22a34bc594d9d24621091d1b91511001a7eea91d6652ea495ce06e27381f70"}, + {file = "aiohttp-3.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:598db66eaf2e04aa0c8900a63b0101fdc5e6b8a7ddd805c56d86efb54eb66672"}, + {file = "aiohttp-3.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c9376e2b09895c8ca8b95362283365eb5c03bdc8428ade80a864160605715f1"}, + {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41473de252e1797c2d2293804e389a6d6986ef37cbb4a25208de537ae32141dd"}, + {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c5857612c9813796960c00767645cb5da815af16dafb32d70c72a8390bbf690"}, + {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffcd828e37dc219a72c9012ec44ad2e7e3066bec6ff3aaa19e7d435dbf4032ca"}, + {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:219a16763dc0294842188ac8a12262b5671817042b35d45e44fd0a697d8c8361"}, + {file = "aiohttp-3.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f694dc8a6a3112059258a725a4ebe9acac5fe62f11c77ac4dcf896edfa78ca28"}, + {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bcc0ea8d5b74a41b621ad4a13d96c36079c81628ccc0b30cfb1603e3dfa3a014"}, + {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:90ec72d231169b4b8d6085be13023ece8fa9b1bb495e4398d847e25218e0f431"}, + {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:cf2a0ac0615842b849f40c4d7f304986a242f1e68286dbf3bd7a835e4f83acfd"}, + {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:0e49b08eafa4f5707ecfb321ab9592717a319e37938e301d462f79b4e860c32a"}, + {file = "aiohttp-3.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2c59e0076ea31c08553e868cec02d22191c086f00b44610f8ab7363a11a5d9d8"}, + {file = "aiohttp-3.9.1-cp38-cp38-win32.whl", hash = "sha256:4831df72b053b1eed31eb00a2e1aff6896fb4485301d4ccb208cac264b648db4"}, + {file = "aiohttp-3.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:3135713c5562731ee18f58d3ad1bf41e1d8883eb68b363f2ffde5b2ea4b84cc7"}, + {file = "aiohttp-3.9.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cfeadf42840c1e870dc2042a232a8748e75a36b52d78968cda6736de55582766"}, + {file = "aiohttp-3.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:70907533db712f7aa791effb38efa96f044ce3d4e850e2d7691abd759f4f0ae0"}, + {file = "aiohttp-3.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cdefe289681507187e375a5064c7599f52c40343a8701761c802c1853a504558"}, + {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7481f581251bb5558ba9f635db70908819caa221fc79ee52a7f58392778c636"}, + {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:49f0c1b3c2842556e5de35f122fc0f0b721334ceb6e78c3719693364d4af8499"}, + {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d406b01a9f5a7e232d1b0d161b40c05275ffbcbd772dc18c1d5a570961a1ca4"}, + {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d8e4450e7fe24d86e86b23cc209e0023177b6d59502e33807b732d2deb6975f"}, + {file = "aiohttp-3.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c0266cd6f005e99f3f51e583012de2778e65af6b73860038b968a0a8888487a"}, + {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab221850108a4a063c5b8a70f00dd7a1975e5a1713f87f4ab26a46e5feac5a0e"}, + {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c88a15f272a0ad3d7773cf3a37cc7b7d077cbfc8e331675cf1346e849d97a4e5"}, + {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:237533179d9747080bcaad4d02083ce295c0d2eab3e9e8ce103411a4312991a0"}, + {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:02ab6006ec3c3463b528374c4cdce86434e7b89ad355e7bf29e2f16b46c7dd6f"}, + {file = "aiohttp-3.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04fa38875e53eb7e354ece1607b1d2fdee2d175ea4e4d745f6ec9f751fe20c7c"}, + {file = "aiohttp-3.9.1-cp39-cp39-win32.whl", hash = "sha256:82eefaf1a996060602f3cc1112d93ba8b201dbf5d8fd9611227de2003dddb3b7"}, + {file = "aiohttp-3.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:9b05d33ff8e6b269e30a7957bd3244ffbce2a7a35a81b81c382629b80af1a8bf"}, + {file = "aiohttp-3.9.1.tar.gz", hash = "sha256:8fc49a87ac269d4529da45871e2ffb6874e87779c3d0e2ccd813c0899221239d"}, +] + +[package.dependencies] +aiosignal = ">=1.1.2" +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +yarl = ">=1.0,<2.0" + +[package.extras] +speedups = ["Brotli", "aiodns", "brotlicffi"] + +[[package]] +name = "aiosignal" +version = "1.3.1" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = false +python-versions = ">=3.7" +files = [ + {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, + {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" + +[[package]] +name = "anyio" +version = "4.2.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, + {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, +] + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] + +[[package]] +name = "attrs" +version = "23.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] + +[[package]] +name = "bitarray" +version = "2.9.2" +description = "efficient arrays of booleans -- C extension" +optional = false +python-versions = "*" +files = [ + {file = "bitarray-2.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:917905de565d9576eb20f53c797c15ba88b9f4f19728acabec8d01eee1d3756a"}, + {file = "bitarray-2.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b35bfcb08b7693ab4bf9059111a6e9f14e07d57ac93cd967c420db58ab9b71e1"}, + {file = "bitarray-2.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ea1923d2e7880f9e1959e035da661767b5a2e16a45dfd57d6aa831e8b65ee1bf"}, + {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0b63a565e8a311cc8348ff1262d5784df0f79d64031d546411afd5dd7ef67d"}, + {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf0620da2b81946d28c0b16f3e3704d38e9837d85ee4f0652816e2609aaa4fed"}, + {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79a9b8b05f2876c7195a2b698c47528e86a73c61ea203394ff8e7a4434bda5c8"}, + {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:345c76b349ff145549652436235c5532e5bfe9db690db6f0a6ad301c62b9ef21"}, + {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e2936f090bf3f4d1771f44f9077ebccdbc0415d2b598d51a969afcb519df505"}, + {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f9346e98fc2abcef90b942973087e2462af6d3e3710e82938078d3493f7fef52"}, + {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e6ec283d4741befb86e8c3ea2e9ac1d17416c956d392107e45263e736954b1f7"}, + {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:962892646599529917ef26266091e4cb3077c88b93c3833a909d68dcc971c4e3"}, + {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e8da5355d7d75a52df5b84750989e34e39919ec7e59fafc4c104cc1607ab2d31"}, + {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:603e7d640e54ad764d2b4da6b61e126259af84f253a20f512dd10689566e5478"}, + {file = "bitarray-2.9.2-cp310-cp310-win32.whl", hash = "sha256:f00079f8e69d75c2a417de7961a77612bb77ef46c09bc74607d86de4740771ef"}, + {file = "bitarray-2.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:1bb33673e7f7190a65f0a940c1ef63266abdb391f4a3e544a47542d40a81f536"}, + {file = "bitarray-2.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fe71fd4b76380c2772f96f1e53a524da7063645d647a4fcd3b651bdd80ca0f2e"}, + {file = "bitarray-2.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d527172919cdea1e13994a66d9708a80c3d33dedcf2f0548e4925e600fef3a3a"}, + {file = "bitarray-2.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:052c5073bdcaa9dd10628d99d37a2f33ec09364b86dd1f6281e2d9f8d3db3060"}, + {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e064caa55a6ed493aca1eda06f8b3f689778bc780a75e6ad7724642ba5dc62f7"}, + {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:508069a04f658210fdeee85a7a0ca84db4bcc110cbb1d21f692caa13210f24a7"}, + {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4da73ebd537d75fa7bccfc2228fcaedea0803f21dd9d0bf0d3b67fef3c4af294"}, + {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cb378eaa65cd43098f11ff5d27e48ee3b956d2c00d2d6b5bfc2a09fe183be47"}, + {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d14c790b91f6cbcd9b718f88ed737c78939980c69ac8c7f03dd7e60040c12951"}, + {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7eea9318293bc0ea6447e9ebfba600a62f3428bea7e9c6d42170ae4f481dbab3"}, + {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b76ffec27c7450b8a334f967366a9ebadaea66ee43f5b530c12861b1a991f503"}, + {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:76b76a07d4ee611405045c6950a1e24c4362b6b44808d4ad6eea75e0dbc59af4"}, + {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:c7d16beeaaab15b075990cd26963d6b5b22e8c5becd131781514a00b8bdd04bd"}, + {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60df43e868a615c7e15117a1e1c2e5e11f48f6457280eba6ddf8fbefbec7da99"}, + {file = "bitarray-2.9.2-cp311-cp311-win32.whl", hash = "sha256:e788608ed7767b7b3bbde6d49058bccdf94df0de9ca75d13aa99020cc7e68095"}, + {file = "bitarray-2.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:a23397da092ef0a8cfe729571da64c2fc30ac18243caa82ac7c4f965087506ff"}, + {file = "bitarray-2.9.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:90e3a281ffe3897991091b7c46fca38c2675bfd4399ffe79dfeded6c52715436"}, + {file = "bitarray-2.9.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bed637b674db5e6c8a97a4a321e3e4d73e72d50b5c6b29950008a93069cc64cd"}, + {file = "bitarray-2.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e49066d251dbbe4e6e3a5c3937d85b589e40e2669ad0eef41a00f82ec17d844b"}, + {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4344e96642e2211fb3a50558feff682c31563a4c64529a931769d40832ca79"}, + {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aeb60962ec4813c539a59fbd4f383509c7222b62c3fb1faa76b54943a613e33a"}, + {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed0f7982f10581bb16553719e5e8f933e003f5b22f7d25a68bdb30fac630a6ff"}, + {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c71d1cabdeee0cdda4669168618f0e46b7dace207b29da7b63aaa1adc2b54081"}, + {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0ef2d0a6f1502d38d911d25609b44c6cc27bee0a4363dd295df78b075041b60"}, + {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6f71d92f533770fb027388b35b6e11988ab89242b883f48a6fe7202d238c61f8"}, + {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ba0734aa300757c924f3faf8148e1b8c247176a0ac8e16aefdf9c1eb19e868f7"}, + {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:d91406f413ccbf4af6ab5ae7bc78f772a95609f9ddd14123db36ef8c37116d95"}, + {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:87abb7f80c0a042f3fe8e5264da1a2756267450bb602110d5327b8eaff7682e7"}, + {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b558ce85579b51a2e38703877d1e93b7728a7af664dd45a34e833534f0b755d"}, + {file = "bitarray-2.9.2-cp312-cp312-win32.whl", hash = "sha256:dac2399ee2889fbdd3472bfc2ede74c34cceb1ccf29a339964281a16eb1d3188"}, + {file = "bitarray-2.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:48a30d718d1a6dfc22a49547450107abe8f4afdf2abdcbe76eb9ed88edc49498"}, + {file = "bitarray-2.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2c6be1b651fad8f3adb7a5aa12c65b612cd9b89530969af941844ae680f7d981"}, + {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5b399ae6ab975257ec359f03b48fc00b1c1cd109471e41903548469b8feae5c"}, + {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b3543c8a1cb286ad105f11c25d8d0f712f41c5c55f90be39f0e5a1376c7d0b0"}, + {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:03adaacb79e2fb8f483ab3a67665eec53bb3fd0cd5dbd7358741aef124688db3"}, + {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ae5b0657380d2581e13e46864d147a52c1e2bbac9f59b59c576e42fa7d10cf0"}, + {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c1f4bf6ea8eb9d7f30808c2e9894237a96650adfecbf5f3643862dc5982f89e"}, + {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a8873089be2aa15494c0f81af1209f6e1237d762c5065bc4766c1b84321e1b50"}, + {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:677e67f50e2559efc677a4366707070933ad5418b8347a603a49a070890b19bc"}, + {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:a620d8ce4ea2f1c73c6b6b1399e14cb68c6915e2be3fad5808c2998ed55b4acf"}, + {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:64115ccabbdbe279c24c367b629c6b1d3da9ed36c7420129e27c338a3971bfee"}, + {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:5d6fb422772e75385b76ad1c52f45a68bd4efafd8be8d0061c11877be74c4d43"}, + {file = "bitarray-2.9.2-cp36-cp36m-win32.whl", hash = "sha256:852e202875dd6dfd6139ce7ec4e98dac2b17d8d25934dc99900831e81c3adaef"}, + {file = "bitarray-2.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:7dfefdcb0dc6a3ba9936063cec65a74595571b375beabe18742b3d91d087eefd"}, + {file = "bitarray-2.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b306c4cf66912511422060f7f5e1149c8bdb404f8e00e600561b0749fdd45659"}, + {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a09c4f81635408e3387348f415521d4b94198c562c23330f560596a6aaa26eaf"}, + {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5361413fd2ecfdf44dc8f065177dc6aba97fa80a91b815586cb388763acf7f8d"}, + {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e8a9475d415ef1eaae7942df6f780fa4dcd48fce32825eda591a17abba869299"}, + {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9b87baa7bfff9a5878fcc1bffe49ecde6e647a72a64b39a69cd8a2992a43a34"}, + {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb6b86cfdfc503e92cb71c68766a24565359136961642504a7cc9faf936d9c88"}, + {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cd56b8ae87ebc71bcacbd73615098e8a8de952ecbb5785b6b4e2b07da8a06e1f"}, + {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3fa909cfd675004aed8b4cc9df352415933656e0155a6209d878b7cb615c787e"}, + {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b069ca9bf728e0c5c5b60e00a89df9af34cc170c695c3bfa3b372d8f40288efb"}, + {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:6067f2f07a7121749858c7daa93c8774325c91590b3e81a299621e347740c2ae"}, + {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:321841cdad1dd0f58fe62e80e9c9c7531f8ebf8be93f047401e930dc47425b1e"}, + {file = "bitarray-2.9.2-cp37-cp37m-win32.whl", hash = "sha256:54e16e32e60973bb83c315de9975bc1bcfc9bd50bb13001c31da159bc49b0ca1"}, + {file = "bitarray-2.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f4dcadb7b8034aa3491ee8f5a69b3d9ba9d7d1e55c3cc1fc45be313e708277f8"}, + {file = "bitarray-2.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c8919fdbd3bb596b104388b56ae4b266eb28da1f2f7dff2e1f9334a21840fe96"}, + {file = "bitarray-2.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eb7a9d8a2e400a1026de341ad48e21670a6261a75b06df162c5c39b0d0e7c8f4"}, + {file = "bitarray-2.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6ec84668dd7b937874a2b2c293cd14ba84f37be0d196dead852e0ada9815d807"}, + {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2de9a31c34e543ae089fd2a5ced01292f725190e379921384f695e2d7184bd3"}, + {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9521f49ae121a17c0a41e5112249e6fa7f6a571245b1118de81fb86e7c1bc1ce"}, + {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6cc6545d6d76542aee3d18c1c9485fb7b9812b8df4ebe52c4535ec42081b48f"}, + {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:856bbe1616425f71c0df5ef2e8755e878d9504d5a531acba58ab4273c52c117a"}, + {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4bba8042ea6ab331ade91bc435d81ad72fddb098e49108610b0ce7780c14e68"}, + {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a035da89c959d98afc813e3c62f052690d67cfd55a36592f25d734b70de7d4b0"}, + {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6d70b1579da7fb71be5a841a1f965d19aca0ef27f629cfc07d06b09aafd0a333"}, + {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:405b83bed28efaae6d86b6ab287c75712ead0adbfab2a1075a1b7ab47dad4d62"}, + {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7eb8be687c50da0b397d5e0ab7ca200b5ebb639e79a9f5e285851d1944c94be9"}, + {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eceb551dfeaf19c609003a69a0cf8264b0efd7abc3791a11dfabf4788daf0d19"}, + {file = "bitarray-2.9.2-cp38-cp38-win32.whl", hash = "sha256:bb198c6ed1edbcdaf3d1fa3c9c9d1cdb7e179a5134ef5ee660b53cdec43b34e7"}, + {file = "bitarray-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:648d2f2685590b0103c67a937c2fb9e09bcc8dfb166f0c7c77bd341902a6f5b3"}, + {file = "bitarray-2.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ea816dc8f8e65841a8bbdd30e921edffeeb6f76efe6a1eb0da147b60d539d1cf"}, + {file = "bitarray-2.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4d0e32530f941c41eddfc77600ec89b65184cb909c549336463a738fab3ed285"}, + {file = "bitarray-2.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4a22266fb416a3b6c258bf7f83c9fe531ba0b755a56986a81ad69dc0f3bcc070"}, + {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc6d3e80dd8239850f2604833ff3168b28909c8a9357abfed95632cccd17e3e7"}, + {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f135e804986b12bf14f2cd1eb86674c47dea86c4c5f0fa13c88978876b97ebe6"}, + {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87580c7f7d14f7ec401eda7adac1e2a25e95153e9c339872c8ae61b3208819a1"}, + {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64b433e26993127732ac7b66a7821b2537c3044355798de7c5fcb0af34b8296f"}, + {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e497c535f2a9b68c69d36631bf2dba243e05eb343b00b9c7bbdc8c601c6802d"}, + {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e40b3cb9fa1edb4e0175d7c06345c49c7925fe93e39ef55ecb0bc40c906b0c09"}, + {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f2f8692f95c9e377eb19ca519d30d1f884b02feb7e115f798de47570a359e43f"}, + {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f0b84fc50b6dbeced4fa390688c07c10a73222810fb0e08392bd1a1b8259de36"}, + {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d656ad38c942e38a470ddbce26b5020e08e1a7ea86b8fd413bb9024b5189993a"}, + {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6ab0f1dbfe5070db98771a56aa14797595acd45a1af9eadfb193851a270e7996"}, + {file = "bitarray-2.9.2-cp39-cp39-win32.whl", hash = "sha256:0a99b23ac845a9ea3157782c97465e6ae026fe0c7c4c1ed1d88f759fd6ea52d9"}, + {file = "bitarray-2.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:9bbcfc7c279e8d74b076e514e669b683f77b4a2a328585b3f16d4c5259c91222"}, + {file = "bitarray-2.9.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:43847799461d8ba71deb4d97b47250c2c2fb66d82cd3cb8b4caf52bb97c03034"}, + {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f44381b0a4bdf64416082f4f0e7140377ae962c0ced6f983c6d7bbfc034040"}, + {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a484061616fb4b158b80789bd3cb511f399d2116525a8b29b6334c68abc2310f"}, + {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ff9e38356cc803e06134cf8ae9758e836ccd1b793135ef3db53c7c5d71e93bc"}, + {file = "bitarray-2.9.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b44105792fbdcfbda3e26ee88786790fda409da4c71f6c2b73888108cf8f062f"}, + {file = "bitarray-2.9.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7e913098de169c7fc890638ce5e171387363eb812579e637c44261460ac00aa2"}, + {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6fe315355cdfe3ed22ef355b8bdc81a805ca4d0949d921576560e5b227a1112"}, + {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f708e91fdbe443f3bec2df394ed42328fb9b0446dff5cb4199023ac6499e09fd"}, + {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b7b09489b71f9f1f64c0fa0977e250ec24500767dab7383ba9912495849cadf"}, + {file = "bitarray-2.9.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:128cc3488176145b9b137fdcf54c1c201809bbb8dd30b260ee40afe915843b43"}, + {file = "bitarray-2.9.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:21f21e7f56206be346bdbda2a6bdb2165a5e6a11821f88fd4911c5a6bbbdc7e2"}, + {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f4dd3af86dd8a617eb6464622fb64ca86e61ce99b59b5c35d8cd33f9c30603d"}, + {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6465de861aff7a2559f226b37982007417eab8c3557543879987f58b453519bd"}, + {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbaf2bb71d6027152d603f1d5f31e0dfd5e50173d06f877bec484e5396d4594b"}, + {file = "bitarray-2.9.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2f32948c86e0d230a296686db28191b67ed229756f84728847daa0c7ab7406e3"}, + {file = "bitarray-2.9.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be94e5a685e60f9d24532af8fe5c268002e9016fa80272a94727f435de3d1003"}, + {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5cc9381fd54f3c23ae1039f977bfd6d041a5c3c1518104f616643c3a5a73b15"}, + {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd926e8ae4d1ed1ac4a8f37212a62886292f692bc1739fde98013bf210c2d175"}, + {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:461a3dafb9d5fda0bb3385dc507d78b1984b49da3fe4c6d56c869a54373b7008"}, + {file = "bitarray-2.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:393cb27fd859af5fd9c16eb26b1c59b17b390ff66b3ae5d0dd258270191baf13"}, + {file = "bitarray-2.9.2.tar.gz", hash = "sha256:a8f286a51a32323715d77755ed959f94bef13972e9a2fe71b609e40e6d27957e"}, +] + +[[package]] +name = "black" +version = "24.1.1" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-24.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2588021038bd5ada078de606f2a804cadd0a3cc6a79cb3e9bb3a8bf581325a4c"}, + {file = "black-24.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a95915c98d6e32ca43809d46d932e2abc5f1f7d582ffbe65a5b4d1588af7445"}, + {file = "black-24.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fa6a0e965779c8f2afb286f9ef798df770ba2b6cee063c650b96adec22c056a"}, + {file = "black-24.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5242ecd9e990aeb995b6d03dc3b2d112d4a78f2083e5a8e86d566340ae80fec4"}, + {file = "black-24.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fc1ec9aa6f4d98d022101e015261c056ddebe3da6a8ccfc2c792cbe0349d48b7"}, + {file = "black-24.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0269dfdea12442022e88043d2910429bed717b2d04523867a85dacce535916b8"}, + {file = "black-24.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3d64db762eae4a5ce04b6e3dd745dcca0fb9560eb931a5be97472e38652a161"}, + {file = "black-24.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:5d7b06ea8816cbd4becfe5f70accae953c53c0e53aa98730ceccb0395520ee5d"}, + {file = "black-24.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e2c8dfa14677f90d976f68e0c923947ae68fa3961d61ee30976c388adc0b02c8"}, + {file = "black-24.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a21725862d0e855ae05da1dd25e3825ed712eaaccef6b03017fe0853a01aa45e"}, + {file = "black-24.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07204d078e25327aad9ed2c64790d681238686bce254c910de640c7cc4fc3aa6"}, + {file = "black-24.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:a83fe522d9698d8f9a101b860b1ee154c1d25f8a82ceb807d319f085b2627c5b"}, + {file = "black-24.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:08b34e85170d368c37ca7bf81cf67ac863c9d1963b2c1780c39102187ec8dd62"}, + {file = "black-24.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7258c27115c1e3b5de9ac6c4f9957e3ee2c02c0b39222a24dc7aa03ba0e986f5"}, + {file = "black-24.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40657e1b78212d582a0edecafef133cf1dd02e6677f539b669db4746150d38f6"}, + {file = "black-24.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e298d588744efda02379521a19639ebcd314fba7a49be22136204d7ed1782717"}, + {file = "black-24.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:34afe9da5056aa123b8bfda1664bfe6fb4e9c6f311d8e4a6eb089da9a9173bf9"}, + {file = "black-24.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:854c06fb86fd854140f37fb24dbf10621f5dab9e3b0c29a690ba595e3d543024"}, + {file = "black-24.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3897ae5a21ca132efa219c029cce5e6bfc9c3d34ed7e892113d199c0b1b444a2"}, + {file = "black-24.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:ecba2a15dfb2d97105be74bbfe5128bc5e9fa8477d8c46766505c1dda5883aac"}, + {file = "black-24.1.1-py3-none-any.whl", hash = "sha256:5cdc2e2195212208fbcae579b931407c1fa9997584f0a415421748aeafff1168"}, + {file = "black-24.1.1.tar.gz", hash = "sha256:48b5760dcbfe5cf97fd4fba23946681f3a81514c6ab8a45b50da67ac8fbc6c7b"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "certifi" +version = "2023.11.17" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "cytoolz" +version = "0.12.2" +description = "Cython implementation of Toolz: High performance functional utilities" +optional = false +python-versions = ">=3.6" +files = [ + {file = "cytoolz-0.12.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bff49986c9bae127928a2f9fd6313146a342bfae8292f63e562f872bd01b871"}, + {file = "cytoolz-0.12.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:908c13f305d34322e11b796de358edaeea47dd2d115c33ca22909c5e8fb036fd"}, + {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:735147aa41b8eeb104da186864b55e2a6623c758000081d19c93d759cd9523e3"}, + {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7d352d4de060604e605abdc5c8a5d0429d5f156cb9866609065d3003454d4cea"}, + {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89247ac220031a4f9f689688bcee42b38fd770d4cce294e5d914afc53b630abe"}, + {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9070ae35c410d644e6df98a8f69f3ed2807e657d0df2a26b2643127cbf6944a5"}, + {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:843500cd3e4884b92fd4037912bc42d5f047108d2c986d36352e880196d465b0"}, + {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6a93644d7996fd696ab7f1f466cd75d718d0a00d5c8118b9fe8c64231dc1f85e"}, + {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:96796594c770bc6587376e74ddc7d9c982d68f47116bb69d90873db5e0ea88b6"}, + {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:48425107fbb1af3f0f2410c004f16be10ffc9374358e5600b57fa543f46f8def"}, + {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:cde6dbb788a4cbc4a80a72aa96386ba4c2b17bdfff3ace0709799adbe16d6476"}, + {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:68ae7091cc73a752f0b938f15bb193de80ca5edf5ae2ea6360d93d3e9228357b"}, + {file = "cytoolz-0.12.2-cp310-cp310-win32.whl", hash = "sha256:997b7e0960072f6bb445402da162f964ea67387b9f18bda2361edcc026e13597"}, + {file = "cytoolz-0.12.2-cp310-cp310-win_amd64.whl", hash = "sha256:663911786dcde3e4a5d88215c722c531c7548903dc07d418418c0d1c768072c0"}, + {file = "cytoolz-0.12.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a7d8b869ded171f6cdf584fc2fc6ae03b30a0e1e37a9daf213a59857a62ed90"}, + {file = "cytoolz-0.12.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9b28787eaf2174e68f0acb3c66f9c6b98bdfeb0930c0d0b08e1941c7aedc8d27"}, + {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00547da587f124b32b072ce52dd5e4b37cf199fedcea902e33c67548523e4678"}, + {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:275d53fd769df2102d6c9fc98e553bd8a9a38926f54d6b20cf29f0dd00bf3b75"}, + {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5556acde785a61d4cf8b8534ae109b023cbd2f9df65ee2afbe070be47c410f8c"}, + {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b41a85b9b9a2530b72b0d3d10e383fc3c2647ae88169d557d5e216f881860318"}, + {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673d6e9e3aa86949343b46ac2b7be266c36e07ce77fa1d40f349e6987a814d6e"}, + {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81e6a9a8fda78a2f4901d2915b25bf620f372997ca1f20a14f7cefef5ad6f6f4"}, + {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fa44215bc31675a6380cd896dadb7f2054a7b94cfb87e53e52af844c65406a54"}, + {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a08b4346350660799d81d4016e748bcb134a9083301d41f9618f64a6077f89f2"}, + {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2fb740482794a72e2e5fec58e4d9b00dcd5a60a8cef68431ff12f2ba0e0d9a7e"}, + {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9007bb1290c79402be6b84bcf9e7a622a073859d61fcee146dc7bc47afe328f3"}, + {file = "cytoolz-0.12.2-cp311-cp311-win32.whl", hash = "sha256:a973f5286758f76824ecf19ae1999f6697371a9121c8f163295d181d19a819d7"}, + {file = "cytoolz-0.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:1ce324d1b413636ea5ee929f79637821f13c9e55e9588f38228947294944d2ed"}, + {file = "cytoolz-0.12.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c08094b9e5d1b6dfb0845a0253cc2655ca64ce70d15162dfdb102e28c8993493"}, + {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baf020f4b708f800b353259cd7575e335a79f1ac912d9dda55b2aa0bf3616e42"}, + {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4416ee86a87180b6a28e7483102c92debc077bec59c67eda8cc63fc52a218ac0"}, + {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6ee222671eed5c5b16a5ad2aea07f0a715b8b199ee534834bc1dd2798f1ade7"}, + {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad92e37be0b106fdbc575a3a669b43b364a5ef334495c9764de4c2d7541f7a99"}, + {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:460c05238fbfe6d848141669d17a751a46c923f9f0c9fd8a3a462ab737623a44"}, + {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9e5075e30be626ef0f9bedf7a15f55ed4d7209e832bc314fdc232dbd61dcbf44"}, + {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:03b58f843f09e73414e82e57f7e8d88f087eaabf8f276b866a40661161da6c51"}, + {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:5e4e612b7ecc9596e7c859cd9e0cd085e6d0c576b4f0d917299595eb56bf9c05"}, + {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:08a0e03f287e45eb694998bb55ac1643372199c659affa8319dfbbdec7f7fb3c"}, + {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b029bdd5a8b6c9a7c0e8fdbe4fc25ffaa2e09b77f6f3462314696e3a20511829"}, + {file = "cytoolz-0.12.2-cp36-cp36m-win32.whl", hash = "sha256:18580d060fa637ff01541640ecde6de832a248df02b8fb57e6dd578f189d62c7"}, + {file = "cytoolz-0.12.2-cp36-cp36m-win_amd64.whl", hash = "sha256:97cf514a9f3426228d8daf880f56488330e4b2948a6d183a106921217850d9eb"}, + {file = "cytoolz-0.12.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18a0f838677f9510aef0330c0096778dd6406d21d4ff9504bf79d85235a18460"}, + {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb081b2b02bf4405c804de1ece6f904916838ab0e057f1446e4ac12fac827960"}, + {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57233e1600560ceb719bed759dc78393edd541b9a3e7fefc3079abd83c26a6ea"}, + {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0295289c4510efa41174850e75bc9188f82b72b1b54d0ea57d1781729c2924d5"}, + {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a92aab8dd1d427ac9bc7480cfd3481dbab0ef024558f2f5a47de672d8a5ffaa"}, + {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51d3495235af09f21aa92a7cdd51504bda640b108b6be834448b774f52852c09"}, + {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9c690b359f503f18bf1c46a6456370e4f6f3fc4320b8774ae69c4f85ecc6c94"}, + {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:481e3129a76ea01adcc0e7097ccb8dbddab1cfc40b6f0e32c670153512957c0f"}, + {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:55e94124af9c8fbb1df54195cc092688fdad0765641b738970b6f1d5ea72e776"}, + {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5616d386dfbfba7c39e9418ba668c734f6ceaacc0130877e8a100cad11e6838b"}, + {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:732d08228fa8d366fec284f7032cc868d28a99fa81fc71e3adf7ecedbcf33a0f"}, + {file = "cytoolz-0.12.2-cp37-cp37m-win32.whl", hash = "sha256:f039c5373f7b314b151432c73219216857b19ab9cb834f0eb5d880f74fc7851c"}, + {file = "cytoolz-0.12.2-cp37-cp37m-win_amd64.whl", hash = "sha256:246368e983eaee9851b15d7755f82030eab4aa82098d2a34f6bef9c689d33fcc"}, + {file = "cytoolz-0.12.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:81074edf3c74bc9bd250d223408a5df0ff745d1f7a462597536cd26b9390e2d6"}, + {file = "cytoolz-0.12.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:960d85ebaa974ecea4e71fa56d098378fa51fd670ee744614cbb95bf95e28fc7"}, + {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c8d0dff4865da54ae825d43e1721925721b19f3b9aca8e730c2ce73dee2c630"}, + {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a9d12436fd64937bd2c9609605f527af7f1a8db6e6637639b44121c0fe715d6"}, + {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd461e402e24929d866f05061d2f8337e3a8456e75e21b72c125abff2477c7f7"}, + {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0568d4da0a9ee9f9f5ab318f6501557f1cfe26d18c96c8e0dac7332ae04c6717"}, + {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:101b5bd32badfc8b1f9c7be04ba3ae04fb47f9c8736590666ce9449bff76e0b1"}, + {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8bb624dbaef4661f5e3625c1e39ad98ecceef281d1380e2774d8084ad0810275"}, + {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3e993804e6b04113d61fdb9541b6df2f096ec265a506dad7437517470919c90f"}, + {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ab911033e5937fc221a2c165acce7f66ae5ac9d3e54bec56f3c9c197a96be574"}, + {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6de6a4bdfaee382c2de2a3580b3ae76fce6105da202bbd835e5efbeae6a9c6e"}, + {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9480b4b327be83c4d29cb88bcace761b11f5e30198ffe2287889455c6819e934"}, + {file = "cytoolz-0.12.2-cp38-cp38-win32.whl", hash = "sha256:4180b2785d1278e6abb36a72ac97c92432db53fa2df00ee943d2c15a33627d31"}, + {file = "cytoolz-0.12.2-cp38-cp38-win_amd64.whl", hash = "sha256:d0086ba8d41d73647b13087a3ca9c020f6bfec338335037e8f5172b4c7c8dce5"}, + {file = "cytoolz-0.12.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d29988bde28a90a00367edcf92afa1a2f7ecf43ea3ae383291b7da6d380ccc25"}, + {file = "cytoolz-0.12.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:24c0d71e9ac91f4466b1bd280f7de43aa4d94682daaf34d85d867a9b479b87cc"}, + {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa436abd4ac9ca71859baf5794614e6ec8fa27362f0162baedcc059048da55f7"}, + {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45c7b4eac7571707269ebc2893facdf87e359cd5c7cfbfa9e6bd8b33fb1079c5"}, + {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:294d24edc747ef4e1b28e54365f713becb844e7898113fafbe3e9165dc44aeea"}, + {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:478051e5ef8278b2429864c8d148efcebdc2be948a61c9a44757cd8c816c98f5"}, + {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14108cafb140dd68fdda610c2bbc6a37bf052cd48cfebf487ed44145f7a2b67f"}, + {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fef7b602ccf8a3c77ab483479ccd7a952a8c5bb1c263156671ba7aaa24d1035"}, + {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9bf51354e15520715f068853e6ab8190e77139940e8b8b633bdb587956a08fb0"}, + {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:388f840fd911d61a96e9e595eaf003f9dc39e847c9060b8e623ab29e556f009b"}, + {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a67f75cc51a2dc7229a8ac84291e4d61dc5abfc8940befcf37a2836d95873340"}, + {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63b31345e20afda2ae30dba246955517a4264464d75e071fc2fa641e88c763ec"}, + {file = "cytoolz-0.12.2-cp39-cp39-win32.whl", hash = "sha256:f6e86ac2b45a95f75c6f744147483e0fc9697ce7dfe1726083324c236f873f8b"}, + {file = "cytoolz-0.12.2-cp39-cp39-win_amd64.whl", hash = "sha256:5998f81bf6a2b28a802521efe14d9fc119f74b64e87b62ad1b0e7c3d8366d0c7"}, + {file = "cytoolz-0.12.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:593e89e2518eaf81e96edcc9ef2c5fca666e8fc922b03d5cb7a7b8964dbee336"}, + {file = "cytoolz-0.12.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff451d614ca1d4227db0ffa627fb51df71968cf0d9baf0210528dad10fdbc3ab"}, + {file = "cytoolz-0.12.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad9ea4a50d2948738351790047d45f2b1a023facc01bf0361988109b177e8b2f"}, + {file = "cytoolz-0.12.2-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbe038bb78d599b5a29d09c438905defaa615a522bc7e12f8016823179439497"}, + {file = "cytoolz-0.12.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d494befe648c13c98c0f3d56d05489c839c9228a32f58e9777305deb6c2c1cee"}, + {file = "cytoolz-0.12.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c26805b6c8dc8565ed91045c44040bf6c0fe5cb5b390c78cd1d9400d08a6cd39"}, + {file = "cytoolz-0.12.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df4e32badb2ccf1773e1e74020b7e3b8caf9e92f842c6be7d14888ecdefc2c6c"}, + {file = "cytoolz-0.12.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce7889dc3701826d519ede93cdff11940fb5567dbdc165dce0e78047eece02b7"}, + {file = "cytoolz-0.12.2-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c820608e7077416f766b148d75e158e454881961881b657cff808529d261dd24"}, + {file = "cytoolz-0.12.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:698da4fa1f7baeea0607738cb1f9877ed1ba50342b29891b0223221679d6f729"}, + {file = "cytoolz-0.12.2.tar.gz", hash = "sha256:31d4b0455d72d914645f803d917daf4f314d115c70de0578d3820deb8b101f66"}, +] + +[package.dependencies] +toolz = ">=0.8.0" + +[package.extras] +cython = ["cython"] + +[[package]] +name = "eth-abi" +version = "5.0.0" +description = "eth_abi: Python utilities for working with Ethereum ABI definitions, especially encoding and decoding" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "eth_abi-5.0.0-py3-none-any.whl", hash = "sha256:936a715d7366ac13cac665cbdaf01cc4aabbe8c2d810d716287a9634f9665e01"}, + {file = "eth_abi-5.0.0.tar.gz", hash = "sha256:89c4454d794d9ed92ad5cb2794698c5cee6b7b3ca6009187d0e282adc7f9b6dc"}, +] + +[package.dependencies] +eth-typing = ">=3.0.0" +eth-utils = ">=2.0.0" +parsimonious = ">=0.9.0,<0.10.0" + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "hypothesis (>=4.18.2,<5.0.0)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-pythonpath (>=0.7.1)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +test = ["eth-hash[pycryptodome]", "hypothesis (>=4.18.2,<5.0.0)", "pytest (>=7.0.0)", "pytest-pythonpath (>=0.7.1)", "pytest-xdist (>=2.4.0)"] +tools = ["hypothesis (>=4.18.2,<5.0.0)"] + +[[package]] +name = "eth-account" +version = "0.10.0" +description = "eth-account: Sign Ethereum transactions and messages with local private keys" +optional = false +python-versions = ">=3.7, <4" +files = [ + {file = "eth-account-0.10.0.tar.gz", hash = "sha256:474a2fccf7286230cf66502565f03b536921d7e1fdfceba198e42160e5ac4bc1"}, + {file = "eth_account-0.10.0-py3-none-any.whl", hash = "sha256:b7a83f506a8edf57926569e5f04471ce3f1700e572d3421b4ad0dad7a26c0978"}, +] + +[package.dependencies] +bitarray = ">=2.4.0" +eth-abi = ">=4.0.0-b.2" +eth-keyfile = ">=0.6.0" +eth-keys = ">=0.4.0" +eth-rlp = ">=0.3.0" +eth-utils = ">=2.0.0" +hexbytes = ">=0.1.0,<0.4.0" +rlp = ">=1.0.0" + +[package.extras] +dev = ["black (>=23)", "build (>=0.9.0)", "bumpversion (>=0.5.3)", "coverage", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "hypothesis (>=4.18.0,<5)", "ipython", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=6.0.0)", "pytest (>=7.0.0)", "pytest-watch (>=4.1.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=5.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +doc = ["sphinx (>=5.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +lint = ["black (>=23)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=6.0.0)"] +test = ["coverage", "hypothesis (>=4.18.0,<5)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "eth-hash" +version = "0.6.0" +description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "eth-hash-0.6.0.tar.gz", hash = "sha256:ae72889e60db6acbb3872c288cfa02ed157f4c27630fcd7f9c8442302c31e478"}, + {file = "eth_hash-0.6.0-py3-none-any.whl", hash = "sha256:9f8daaa345764f8871dc461855049ac54ae4291d780279bce6fce7f24e3f17d3"}, +] + +[package.dependencies] +pycryptodome = {version = ">=3.6.6,<4", optional = true, markers = "extra == \"pycryptodome\""} + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +pycryptodome = ["pycryptodome (>=3.6.6,<4)"] +pysha3 = ["pysha3 (>=1.0.0,<2.0.0)", "safe-pysha3 (>=1.0.0)"] +test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "eth-keyfile" +version = "0.7.0" +description = "eth-keyfile: A library for handling the encrypted keyfiles used to store ethereum private keys" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "eth-keyfile-0.7.0.tar.gz", hash = "sha256:6bdb8110c3a50439deb68a04c93c9d5ddd5402353bfae1bf4cfca1d6dff14fcf"}, + {file = "eth_keyfile-0.7.0-py3-none-any.whl", hash = "sha256:6a89b231a2fe250c3a8f924f2695bb9cce33ddd0d6f7ebbcdacd183d7f83d537"}, +] + +[package.dependencies] +eth-keys = ">=0.4.0" +eth-utils = ">=2" +pycryptodome = ">=3.6.6,<4" + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["towncrier (>=21,<22)"] +test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "eth-keys" +version = "0.5.0" +description = "eth-keys: Common API for Ethereum key operations" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "eth-keys-0.5.0.tar.gz", hash = "sha256:a0abccb83f3d84322591a2c047a1e3aa52ea86b185fa3e82ce311d120ca2791e"}, + {file = "eth_keys-0.5.0-py3-none-any.whl", hash = "sha256:b2bed3ff3bcede68cc0cd4458c7147baaeaac1211a1efdb6ca019f9d3d989f2b"}, +] + +[package.dependencies] +eth-typing = ">=3" +eth-utils = ">=2" + +[package.extras] +coincurve = ["coincurve (>=12.0.0)"] +dev = ["asn1tools (>=0.146.2)", "build (>=0.9.0)", "bumpversion (>=0.5.3)", "coincurve (>=12.0.0)", "eth-hash[pysha3]", "factory-boy (>=3.0.1)", "hypothesis (>=5.10.3,<6)", "ipython", "pre-commit (>=3.4.0)", "pyasn1 (>=0.4.5)", "pytest (>=7.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["towncrier (>=21,<22)"] +test = ["asn1tools (>=0.146.2)", "eth-hash[pysha3]", "factory-boy (>=3.0.1)", "hypothesis (>=5.10.3,<6)", "pyasn1 (>=0.4.5)", "pytest (>=7.0.0)"] + +[[package]] +name = "eth-rlp" +version = "1.0.0" +description = "eth-rlp: RLP definitions for common Ethereum objects in Python" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "eth-rlp-1.0.0.tar.gz", hash = "sha256:a988d713a36452e7c6da71186798343f687eaf3aeb7f99266750dd9e1f754c7b"}, + {file = "eth_rlp-1.0.0-py3-none-any.whl", hash = "sha256:5029b90334bf21d4b728278b42d4672700c34e65ef34a70610b8fffcc8255fc8"}, +] + +[package.dependencies] +eth-utils = ">=2.0.0" +hexbytes = ">=0.1.0,<1" +rlp = ">=0.6.0" + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +test = ["eth-hash[pycryptodome]", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "eth-typing" +version = "4.0.0" +description = "eth-typing: Common type annotations for ethereum python packages" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "eth-typing-4.0.0.tar.gz", hash = "sha256:9af0b6beafbc5c2e18daf19da5f5a68315023172c4e79d149e12ad10a3d3f731"}, + {file = "eth_typing-4.0.0-py3-none-any.whl", hash = "sha256:7e556bea322b6e8c0a231547b736c258e10ce9eed5ddc254f51031b12af66a16"}, +] + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "eth-utils" +version = "3.0.0" +description = "eth-utils: Common utility functions for python code that interacts with Ethereum" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "eth-utils-3.0.0.tar.gz", hash = "sha256:8721869568448349bceae63c277b75758d11e0dc190e7ef31e161b89619458f1"}, + {file = "eth_utils-3.0.0-py3-none-any.whl", hash = "sha256:9a284106acf6f6ce91ddf792489cf8bd4c681fd5ae7653d2f3d5d100be5c3905"}, +] + +[package.dependencies] +cytoolz = {version = ">=0.10.1", markers = "implementation_name == \"cpython\""} +eth-hash = ">=0.3.1" +eth-typing = ">=3.0.0" +toolz = {version = ">0.8.2", markers = "implementation_name == \"pypy\""} + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "hypothesis (>=4.43.0)", "ipython", "mypy (==1.5.1)", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +test = ["hypothesis (>=4.43.0)", "mypy (==1.5.1)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "frozenlist" +version = "1.4.1" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = false +python-versions = ">=3.8" +files = [ + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, + {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, + {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, + {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, + {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, + {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, + {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, + {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, + {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, + {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, + {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, + {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, + {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, +] + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "hexbytes" +version = "0.3.1" +description = "hexbytes: Python `bytes` subclass that decodes hex, with a readable console output" +optional = false +python-versions = ">=3.7, <4" +files = [ + {file = "hexbytes-0.3.1-py3-none-any.whl", hash = "sha256:383595ad75026cf00abd570f44b368c6cdac0c6becfae5c39ff88829877f8a59"}, + {file = "hexbytes-0.3.1.tar.gz", hash = "sha256:a3fe35c6831ee8fafd048c4c086b986075fc14fd46258fa24ecb8d65745f9a9d"}, +] + +[package.extras] +dev = ["black (>=22)", "bumpversion (>=0.5.3)", "eth-utils (>=1.0.1,<3)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "hypothesis (>=3.44.24,<=6.31.6)", "ipython", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=5.0.0)", "pytest (>=7.0.0)", "pytest-watch (>=4.1.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=5.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +doc = ["sphinx (>=5.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +lint = ["black (>=22)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=5.0.0)"] +test = ["eth-utils (>=1.0.1,<3)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "httpcore" +version = "1.0.2" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, + {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<0.23.0)"] + +[[package]] +name = "httpx" +version = "0.26.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.26.0-py3-none-any.whl", hash = "sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd"}, + {file = "httpx-0.26.0.tar.gz", hash = "sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "idna" +version = "3.6" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + +[[package]] +name = "isort" +version = "5.13.2" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] + +[package.extras] +colors = ["colorama (>=0.4.6)"] + +[[package]] +name = "jsonschema" +version = "4.20.0" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.20.0-py3-none-any.whl", hash = "sha256:ed6231f0429ecf966f5bc8dfef245998220549cbbcf140f913b7464c52c3b6b3"}, + {file = "jsonschema-4.20.0.tar.gz", hash = "sha256:4f614fd46d8d61258610998997743ec5492a648b33cf478c1ddc23ed4598a5fa"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rpds-py = ">=0.7.1" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jsonschema-specifications" +version = "2023.12.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + +[[package]] +name = "lru-dict" +version = "1.2.0" +description = "An Dict like LRU container." +optional = false +python-versions = "*" +files = [ + {file = "lru-dict-1.2.0.tar.gz", hash = "sha256:13c56782f19d68ddf4d8db0170041192859616514c706b126d0df2ec72a11bd7"}, + {file = "lru_dict-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:de906e5486b5c053d15b7731583c25e3c9147c288ac8152a6d1f9bccdec72641"}, + {file = "lru_dict-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604d07c7604b20b3130405d137cae61579578b0e8377daae4125098feebcb970"}, + {file = "lru_dict-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:203b3e78d03d88f491fa134f85a42919020686b6e6f2d09759b2f5517260c651"}, + {file = "lru_dict-1.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:020b93870f8c7195774cbd94f033b96c14f51c57537969965c3af300331724fe"}, + {file = "lru_dict-1.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1184d91cfebd5d1e659d47f17a60185bbf621635ca56dcdc46c6a1745d25df5c"}, + {file = "lru_dict-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fc42882b554a86e564e0b662da47b8a4b32fa966920bd165e27bb8079a323bc1"}, + {file = "lru_dict-1.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:18ee88ada65bd2ffd483023be0fa1c0a6a051ef666d1cd89e921dcce134149f2"}, + {file = "lru_dict-1.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:756230c22257597b7557eaef7f90484c489e9ba78e5bb6ab5a5bcfb6b03cb075"}, + {file = "lru_dict-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c4da599af36618881748b5db457d937955bb2b4800db891647d46767d636c408"}, + {file = "lru_dict-1.2.0-cp310-cp310-win32.whl", hash = "sha256:35a142a7d1a4fd5d5799cc4f8ab2fff50a598d8cee1d1c611f50722b3e27874f"}, + {file = "lru_dict-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:6da5b8099766c4da3bf1ed6e7d7f5eff1681aff6b5987d1258a13bd2ed54f0c9"}, + {file = "lru_dict-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b20b7c9beb481e92e07368ebfaa363ed7ef61e65ffe6e0edbdbaceb33e134124"}, + {file = "lru_dict-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22147367b296be31cc858bf167c448af02435cac44806b228c9be8117f1bfce4"}, + {file = "lru_dict-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34a3091abeb95e707f381a8b5b7dc8e4ee016316c659c49b726857b0d6d1bd7a"}, + {file = "lru_dict-1.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:877801a20f05c467126b55338a4e9fa30e2a141eb7b0b740794571b7d619ee11"}, + {file = "lru_dict-1.2.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d3336e901acec897bcd318c42c2b93d5f1d038e67688f497045fc6bad2c0be7"}, + {file = "lru_dict-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8dafc481d2defb381f19b22cc51837e8a42631e98e34b9e0892245cc96593deb"}, + {file = "lru_dict-1.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:87bbad3f5c3de8897b8c1263a9af73bbb6469fb90e7b57225dad89b8ef62cd8d"}, + {file = "lru_dict-1.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:25f9e0bc2fe8f41c2711ccefd2871f8a5f50a39e6293b68c3dec576112937aad"}, + {file = "lru_dict-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ae301c282a499dc1968dd633cfef8771dd84228ae9d40002a3ea990e4ff0c469"}, + {file = "lru_dict-1.2.0-cp311-cp311-win32.whl", hash = "sha256:c9617583173a29048e11397f165501edc5ae223504a404b2532a212a71ecc9ed"}, + {file = "lru_dict-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6b7a031e47421d4b7aa626b8c91c180a9f037f89e5d0a71c4bb7afcf4036c774"}, + {file = "lru_dict-1.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ea2ac3f7a7a2f32f194c84d82a034e66780057fd908b421becd2f173504d040e"}, + {file = "lru_dict-1.2.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd46c94966f631a81ffe33eee928db58e9fbee15baba5923d284aeadc0e0fa76"}, + {file = "lru_dict-1.2.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:086ce993414f0b28530ded7e004c77dc57c5748fa6da488602aa6e7f79e6210e"}, + {file = "lru_dict-1.2.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df25a426446197488a6702954dcc1de511deee20c9db730499a2aa83fddf0df1"}, + {file = "lru_dict-1.2.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c53b12b89bd7a6c79f0536ff0d0a84fdf4ab5f6252d94b24b9b753bd9ada2ddf"}, + {file = "lru_dict-1.2.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f9484016e6765bd295708cccc9def49f708ce07ac003808f69efa386633affb9"}, + {file = "lru_dict-1.2.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d0f7ec902a0097ac39f1922c89be9eaccf00eb87751e28915320b4f72912d057"}, + {file = "lru_dict-1.2.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:981ef3edc82da38d39eb60eae225b88a538d47b90cce2e5808846fd2cf64384b"}, + {file = "lru_dict-1.2.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e25b2e90a032dc248213af7f3f3e975e1934b204f3b16aeeaeaff27a3b65e128"}, + {file = "lru_dict-1.2.0-cp36-cp36m-win32.whl", hash = "sha256:59f3df78e94e07959f17764e7fa7ca6b54e9296953d2626a112eab08e1beb2db"}, + {file = "lru_dict-1.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:de24b47159e07833aeab517d9cb1c3c5c2d6445cc378b1c2f1d8d15fb4841d63"}, + {file = "lru_dict-1.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d0dd4cd58220351233002f910e35cc01d30337696b55c6578f71318b137770f9"}, + {file = "lru_dict-1.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a87bdc291718bbdf9ea4be12ae7af26cbf0706fa62c2ac332748e3116c5510a7"}, + {file = "lru_dict-1.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05fb8744f91f58479cbe07ed80ada6696ec7df21ea1740891d4107a8dd99a970"}, + {file = "lru_dict-1.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00f6e8a3fc91481b40395316a14c94daa0f0a5de62e7e01a7d589f8d29224052"}, + {file = "lru_dict-1.2.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b172fce0a0ffc0fa6d282c14256d5a68b5db1e64719c2915e69084c4b6bf555"}, + {file = "lru_dict-1.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e707d93bae8f0a14e6df1ae8b0f076532b35f00e691995f33132d806a88e5c18"}, + {file = "lru_dict-1.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b9ec7a4a0d6b8297102aa56758434fb1fca276a82ed7362e37817407185c3abb"}, + {file = "lru_dict-1.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:f404dcc8172da1f28da9b1f0087009578e608a4899b96d244925c4f463201f2a"}, + {file = "lru_dict-1.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1171ad3bff32aa8086778be4a3bdff595cc2692e78685bcce9cb06b96b22dcc2"}, + {file = "lru_dict-1.2.0-cp37-cp37m-win32.whl", hash = "sha256:0c316dfa3897fabaa1fe08aae89352a3b109e5f88b25529bc01e98ac029bf878"}, + {file = "lru_dict-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5919dd04446bc1ee8d6ecda2187deeebfff5903538ae71083e069bc678599446"}, + {file = "lru_dict-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fbf36c5a220a85187cacc1fcb7dd87070e04b5fc28df7a43f6842f7c8224a388"}, + {file = "lru_dict-1.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:712e71b64da181e1c0a2eaa76cd860265980cd15cb0e0498602b8aa35d5db9f8"}, + {file = "lru_dict-1.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f54908bf91280a9b8fa6a8c8f3c2f65850ce6acae2852bbe292391628ebca42f"}, + {file = "lru_dict-1.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3838e33710935da2ade1dd404a8b936d571e29268a70ff4ca5ba758abb3850df"}, + {file = "lru_dict-1.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5d5a5f976b39af73324f2b793862859902ccb9542621856d51a5993064f25e4"}, + {file = "lru_dict-1.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8bda3a9afd241ee0181661decaae25e5336ce513ac268ab57da737eacaa7871f"}, + {file = "lru_dict-1.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:bd2cd1b998ea4c8c1dad829fc4fa88aeed4dee555b5e03c132fc618e6123f168"}, + {file = "lru_dict-1.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b55753ee23028ba8644fd22e50de7b8f85fa60b562a0fafaad788701d6131ff8"}, + {file = "lru_dict-1.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e51fa6a203fa91d415f3b2900e5748ec8e06ad75777c98cc3aeb3983ca416d7"}, + {file = "lru_dict-1.2.0-cp38-cp38-win32.whl", hash = "sha256:cd6806313606559e6c7adfa0dbeb30fc5ab625f00958c3d93f84831e7a32b71e"}, + {file = "lru_dict-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d90a70c53b0566084447c3ef9374cc5a9be886e867b36f89495f211baabd322"}, + {file = "lru_dict-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3ea7571b6bf2090a85ff037e6593bbafe1a8598d5c3b4560eb56187bcccb4dc"}, + {file = "lru_dict-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:287c2115a59c1c9ed0d5d8ae7671e594b1206c36ea9df2fca6b17b86c468ff99"}, + {file = "lru_dict-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5ccfd2291c93746a286c87c3f895165b697399969d24c54804ec3ec559d4e43"}, + {file = "lru_dict-1.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b710f0f4d7ec4f9fa89dfde7002f80bcd77de8024017e70706b0911ea086e2ef"}, + {file = "lru_dict-1.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5345bf50e127bd2767e9fd42393635bbc0146eac01f6baf6ef12c332d1a6a329"}, + {file = "lru_dict-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:291d13f85224551913a78fe695cde04cbca9dcb1d84c540167c443eb913603c9"}, + {file = "lru_dict-1.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d5bb41bc74b321789803d45b124fc2145c1b3353b4ad43296d9d1d242574969b"}, + {file = "lru_dict-1.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0facf49b053bf4926d92d8d5a46fe07eecd2af0441add0182c7432d53d6da667"}, + {file = "lru_dict-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:987b73a06bcf5a95d7dc296241c6b1f9bc6cda42586948c9dabf386dc2bef1cd"}, + {file = "lru_dict-1.2.0-cp39-cp39-win32.whl", hash = "sha256:231d7608f029dda42f9610e5723614a35b1fff035a8060cf7d2be19f1711ace8"}, + {file = "lru_dict-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:71da89e134747e20ed5b8ad5b4ee93fc5b31022c2b71e8176e73c5a44699061b"}, + {file = "lru_dict-1.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:21b3090928c7b6cec509e755cc3ab742154b33660a9b433923bd12c37c448e3e"}, + {file = "lru_dict-1.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaecd7085212d0aa4cd855f38b9d61803d6509731138bf798a9594745953245b"}, + {file = "lru_dict-1.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ead83ac59a29d6439ddff46e205ce32f8b7f71a6bd8062347f77e232825e3d0a"}, + {file = "lru_dict-1.2.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:312b6b2a30188586fe71358f0f33e4bac882d33f5e5019b26f084363f42f986f"}, + {file = "lru_dict-1.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:b30122e098c80e36d0117810d46459a46313421ce3298709170b687dc1240b02"}, + {file = "lru_dict-1.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f010cfad3ab10676e44dc72a813c968cd586f37b466d27cde73d1f7f1ba158c2"}, + {file = "lru_dict-1.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20f5f411f7751ad9a2c02e80287cedf69ae032edd321fe696e310d32dd30a1f8"}, + {file = "lru_dict-1.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:afdadd73304c9befaed02eb42f5f09fdc16288de0a08b32b8080f0f0f6350aa6"}, + {file = "lru_dict-1.2.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7ab0c10c4fa99dc9e26b04e6b62ac32d2bcaea3aad9b81ec8ce9a7aa32b7b1b"}, + {file = "lru_dict-1.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:edad398d5d402c43d2adada390dd83c74e46e020945ff4df801166047013617e"}, + {file = "lru_dict-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:91d577a11b84387013815b1ad0bb6e604558d646003b44c92b3ddf886ad0f879"}, + {file = "lru_dict-1.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb12f19cdf9c4f2d9aa259562e19b188ff34afab28dd9509ff32a3f1c2c29326"}, + {file = "lru_dict-1.2.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e4c85aa8844bdca3c8abac3b7f78da1531c74e9f8b3e4890c6e6d86a5a3f6c0"}, + {file = "lru_dict-1.2.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c6acbd097b15bead4de8e83e8a1030bb4d8257723669097eac643a301a952f0"}, + {file = "lru_dict-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b6613daa851745dd22b860651de930275be9d3e9373283a2164992abacb75b62"}, +] + +[package.extras] +test = ["pytest"] + +[[package]] +name = "multidict" +version = "6.0.4" +description = "multidict implementation" +optional = false +python-versions = ">=3.7" +files = [ + {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, + {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, + {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, + {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, + {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, + {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, + {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, + {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, + {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, + {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, + {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, + {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, + {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, + {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, + {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, + {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, + {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, + {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, + {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, + {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, + {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, + {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, + {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, + {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, + {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, + {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, + {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, + {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "parsimonious" +version = "0.9.0" +description = "(Soon to be) the fastest pure-Python PEG parser I could muster" +optional = false +python-versions = "*" +files = [ + {file = "parsimonious-0.9.0.tar.gz", hash = "sha256:b2ad1ae63a2f65bd78f5e0a8ac510a98f3607a43f1db2a8d46636a5d9e4a30c1"}, +] + +[package.dependencies] +regex = ">=2022.3.15" + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.2.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] + +[[package]] +name = "protobuf" +version = "4.25.2" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "protobuf-4.25.2-cp310-abi3-win32.whl", hash = "sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6"}, + {file = "protobuf-4.25.2-cp310-abi3-win_amd64.whl", hash = "sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9"}, + {file = "protobuf-4.25.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d"}, + {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62"}, + {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020"}, + {file = "protobuf-4.25.2-cp38-cp38-win32.whl", hash = "sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61"}, + {file = "protobuf-4.25.2-cp38-cp38-win_amd64.whl", hash = "sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62"}, + {file = "protobuf-4.25.2-cp39-cp39-win32.whl", hash = "sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3"}, + {file = "protobuf-4.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0"}, + {file = "protobuf-4.25.2-py3-none-any.whl", hash = "sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830"}, + {file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"}, +] + +[[package]] +name = "pycryptodome" +version = "3.20.0" +description = "Cryptographic library for Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690"}, + {file = "pycryptodome-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc"}, + {file = "pycryptodome-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818"}, + {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044"}, + {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c"}, + {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c"}, + {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4"}, + {file = "pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72"}, + {file = "pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9"}, + {file = "pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a"}, + {file = "pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea"}, + {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5"}, + {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e"}, + {file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"}, +] + +[[package]] +name = "pyflakes" +version = "3.2.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, + {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, +] + +[[package]] +name = "pyunormalize" +version = "15.1.0" +description = "Unicode normalization forms (NFC, NFKC, NFD, NFKD). A library independent from the Python core Unicode database." +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyunormalize-15.1.0.tar.gz", hash = "sha256:cf4a87451a0f1cb76911aa97f432f4579e1f564a2f0c84ce488c73a73901b6c1"}, +] + +[[package]] +name = "pywin32" +version = "306" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, + {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, + {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, + {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, + {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, + {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, + {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, +] + +[[package]] +name = "referencing" +version = "0.32.1" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.32.1-py3-none-any.whl", hash = "sha256:7e4dc12271d8e15612bfe35792f5ea1c40970dadf8624602e33db2758f7ee554"}, + {file = "referencing-0.32.1.tar.gz", hash = "sha256:3c57da0513e9563eb7e203ebe9bb3a1b509b042016433bd1e45a2853466c3dd3"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + +[[package]] +name = "regex" +version = "2023.12.25" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.7" +files = [ + {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0694219a1d54336fd0445ea382d49d36882415c0134ee1e8332afd1529f0baa5"}, + {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b014333bd0217ad3d54c143de9d4b9a3ca1c5a29a6d0d554952ea071cff0f1f8"}, + {file = "regex-2023.12.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d865984b3f71f6d0af64d0d88f5733521698f6c16f445bb09ce746c92c97c586"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0eabac536b4cc7f57a5f3d095bfa557860ab912f25965e08fe1545e2ed8b4c"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c25a8ad70e716f96e13a637802813f65d8a6760ef48672aa3502f4c24ea8b400"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9b6d73353f777630626f403b0652055ebfe8ff142a44ec2cf18ae470395766e"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9cc99d6946d750eb75827cb53c4371b8b0fe89c733a94b1573c9dd16ea6c9e4"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88d1f7bef20c721359d8675f7d9f8e414ec5003d8f642fdfd8087777ff7f94b5"}, + {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cb3fe77aec8f1995611f966d0c656fdce398317f850d0e6e7aebdfe61f40e1cd"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7aa47c2e9ea33a4a2a05f40fcd3ea36d73853a2aae7b4feab6fc85f8bf2c9704"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:df26481f0c7a3f8739fecb3e81bc9da3fcfae34d6c094563b9d4670b047312e1"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c40281f7d70baf6e0db0c2f7472b31609f5bc2748fe7275ea65a0b4601d9b392"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d94a1db462d5690ebf6ae86d11c5e420042b9898af5dcf278bd97d6bda065423"}, + {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ba1b30765a55acf15dce3f364e4928b80858fa8f979ad41f862358939bdd1f2f"}, + {file = "regex-2023.12.25-cp310-cp310-win32.whl", hash = "sha256:150c39f5b964e4d7dba46a7962a088fbc91f06e606f023ce57bb347a3b2d4630"}, + {file = "regex-2023.12.25-cp310-cp310-win_amd64.whl", hash = "sha256:09da66917262d9481c719599116c7dc0c321ffcec4b1f510c4f8a066f8768105"}, + {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1b9d811f72210fa9306aeb88385b8f8bcef0dfbf3873410413c00aa94c56c2b6"}, + {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d902a43085a308cef32c0d3aea962524b725403fd9373dea18110904003bac97"}, + {file = "regex-2023.12.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d166eafc19f4718df38887b2bbe1467a4f74a9830e8605089ea7a30dd4da8887"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7ad32824b7f02bb3c9f80306d405a1d9b7bb89362d68b3c5a9be53836caebdb"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:636ba0a77de609d6510235b7f0e77ec494d2657108f777e8765efc060094c98c"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fda75704357805eb953a3ee15a2b240694a9a514548cd49b3c5124b4e2ad01b"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f72cbae7f6b01591f90814250e636065850c5926751af02bb48da94dfced7baa"}, + {file = "regex-2023.12.25-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db2a0b1857f18b11e3b0e54ddfefc96af46b0896fb678c85f63fb8c37518b3e7"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7502534e55c7c36c0978c91ba6f61703faf7ce733715ca48f499d3dbbd7657e0"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e8c7e08bb566de4faaf11984af13f6bcf6a08f327b13631d41d62592681d24fe"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:283fc8eed679758de38fe493b7d7d84a198b558942b03f017b1f94dda8efae80"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f44dd4d68697559d007462b0a3a1d9acd61d97072b71f6d1968daef26bc744bd"}, + {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:67d3ccfc590e5e7197750fcb3a2915b416a53e2de847a728cfa60141054123d4"}, + {file = "regex-2023.12.25-cp311-cp311-win32.whl", hash = "sha256:68191f80a9bad283432385961d9efe09d783bcd36ed35a60fb1ff3f1ec2efe87"}, + {file = "regex-2023.12.25-cp311-cp311-win_amd64.whl", hash = "sha256:7d2af3f6b8419661a0c421584cfe8aaec1c0e435ce7e47ee2a97e344b98f794f"}, + {file = "regex-2023.12.25-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8a0ccf52bb37d1a700375a6b395bff5dd15c50acb745f7db30415bae3c2b0715"}, + {file = "regex-2023.12.25-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c3c4a78615b7762740531c27cf46e2f388d8d727d0c0c739e72048beb26c8a9d"}, + {file = "regex-2023.12.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ad83e7545b4ab69216cef4cc47e344d19622e28aabec61574b20257c65466d6a"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7a635871143661feccce3979e1727c4e094f2bdfd3ec4b90dfd4f16f571a87a"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d498eea3f581fbe1b34b59c697512a8baef88212f92e4c7830fcc1499f5b45a5"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43f7cd5754d02a56ae4ebb91b33461dc67be8e3e0153f593c509e21d219c5060"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51f4b32f793812714fd5307222a7f77e739b9bc566dc94a18126aba3b92b98a3"}, + {file = "regex-2023.12.25-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba99d8077424501b9616b43a2d208095746fb1284fc5ba490139651f971d39d9"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4bfc2b16e3ba8850e0e262467275dd4d62f0d045e0e9eda2bc65078c0110a11f"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8c2c19dae8a3eb0ea45a8448356ed561be843b13cbc34b840922ddf565498c1c"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:60080bb3d8617d96f0fb7e19796384cc2467447ef1c491694850ebd3670bc457"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b77e27b79448e34c2c51c09836033056a0547aa360c45eeeb67803da7b0eedaf"}, + {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:518440c991f514331f4850a63560321f833979d145d7d81186dbe2f19e27ae3d"}, + {file = "regex-2023.12.25-cp312-cp312-win32.whl", hash = "sha256:e2610e9406d3b0073636a3a2e80db05a02f0c3169b5632022b4e81c0364bcda5"}, + {file = "regex-2023.12.25-cp312-cp312-win_amd64.whl", hash = "sha256:cc37b9aeebab425f11f27e5e9e6cf580be7206c6582a64467a14dda211abc232"}, + {file = "regex-2023.12.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:da695d75ac97cb1cd725adac136d25ca687da4536154cdc2815f576e4da11c69"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d126361607b33c4eb7b36debc173bf25d7805847346dd4d99b5499e1fef52bc7"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4719bb05094d7d8563a450cf8738d2e1061420f79cfcc1fa7f0a44744c4d8f73"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dd58946bce44b53b06d94aa95560d0b243eb2fe64227cba50017a8d8b3cd3e2"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22a86d9fff2009302c440b9d799ef2fe322416d2d58fc124b926aa89365ec482"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2aae8101919e8aa05ecfe6322b278f41ce2994c4a430303c4cd163fef746e04f"}, + {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e692296c4cc2873967771345a876bcfc1c547e8dd695c6b89342488b0ea55cd8"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:263ef5cc10979837f243950637fffb06e8daed7f1ac1e39d5910fd29929e489a"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d6f7e255e5fa94642a0724e35406e6cb7001c09d476ab5fce002f652b36d0c39"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:88ad44e220e22b63b0f8f81f007e8abbb92874d8ced66f32571ef8beb0643b2b"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:3a17d3ede18f9cedcbe23d2daa8a2cd6f59fe2bf082c567e43083bba3fb00347"}, + {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d15b274f9e15b1a0b7a45d2ac86d1f634d983ca40d6b886721626c47a400bf39"}, + {file = "regex-2023.12.25-cp37-cp37m-win32.whl", hash = "sha256:ed19b3a05ae0c97dd8f75a5d8f21f7723a8c33bbc555da6bbe1f96c470139d3c"}, + {file = "regex-2023.12.25-cp37-cp37m-win_amd64.whl", hash = "sha256:a6d1047952c0b8104a1d371f88f4ab62e6275567d4458c1e26e9627ad489b445"}, + {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b43523d7bc2abd757119dbfb38af91b5735eea45537ec6ec3a5ec3f9562a1c53"}, + {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:efb2d82f33b2212898f1659fb1c2e9ac30493ac41e4d53123da374c3b5541e64"}, + {file = "regex-2023.12.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7fca9205b59c1a3d5031f7e64ed627a1074730a51c2a80e97653e3e9fa0d415"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086dd15e9435b393ae06f96ab69ab2d333f5d65cbe65ca5a3ef0ec9564dfe770"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e81469f7d01efed9b53740aedd26085f20d49da65f9c1f41e822a33992cb1590"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34e4af5b27232f68042aa40a91c3b9bb4da0eeb31b7632e0091afc4310afe6cb"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9852b76ab558e45b20bf1893b59af64a28bd3820b0c2efc80e0a70a4a3ea51c1"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff100b203092af77d1a5a7abe085b3506b7eaaf9abf65b73b7d6905b6cb76988"}, + {file = "regex-2023.12.25-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cc038b2d8b1470364b1888a98fd22d616fba2b6309c5b5f181ad4483e0017861"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:094ba386bb5c01e54e14434d4caabf6583334090865b23ef58e0424a6286d3dc"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5cd05d0f57846d8ba4b71d9c00f6f37d6b97d5e5ef8b3c3840426a475c8f70f4"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:9aa1a67bbf0f957bbe096375887b2505f5d8ae16bf04488e8b0f334c36e31360"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:98a2636994f943b871786c9e82bfe7883ecdaba2ef5df54e1450fa9869d1f756"}, + {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37f8e93a81fc5e5bd8db7e10e62dc64261bcd88f8d7e6640aaebe9bc180d9ce2"}, + {file = "regex-2023.12.25-cp38-cp38-win32.whl", hash = "sha256:d78bd484930c1da2b9679290a41cdb25cc127d783768a0369d6b449e72f88beb"}, + {file = "regex-2023.12.25-cp38-cp38-win_amd64.whl", hash = "sha256:b521dcecebc5b978b447f0f69b5b7f3840eac454862270406a39837ffae4e697"}, + {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f7bc09bc9c29ebead055bcba136a67378f03d66bf359e87d0f7c759d6d4ffa31"}, + {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e14b73607d6231f3cc4622809c196b540a6a44e903bcfad940779c80dffa7be7"}, + {file = "regex-2023.12.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9eda5f7a50141291beda3edd00abc2d4a5b16c29c92daf8d5bd76934150f3edc"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc6bb9aa69aacf0f6032c307da718f61a40cf970849e471254e0e91c56ffca95"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:298dc6354d414bc921581be85695d18912bea163a8b23cac9a2562bbcd5088b1"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f4e475a80ecbd15896a976aa0b386c5525d0ed34d5c600b6d3ebac0a67c7ddf"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531ac6cf22b53e0696f8e1d56ce2396311254eb806111ddd3922c9d937151dae"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22f3470f7524b6da61e2020672df2f3063676aff444db1daa283c2ea4ed259d6"}, + {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:89723d2112697feaa320c9d351e5f5e7b841e83f8b143dba8e2d2b5f04e10923"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0ecf44ddf9171cd7566ef1768047f6e66975788258b1c6c6ca78098b95cf9a3d"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:905466ad1702ed4acfd67a902af50b8db1feeb9781436372261808df7a2a7bca"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:4558410b7a5607a645e9804a3e9dd509af12fb72b9825b13791a37cd417d73a5"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7e316026cc1095f2a3e8cc012822c99f413b702eaa2ca5408a513609488cb62f"}, + {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3b1de218d5375cd6ac4b5493e0b9f3df2be331e86520f23382f216c137913d20"}, + {file = "regex-2023.12.25-cp39-cp39-win32.whl", hash = "sha256:11a963f8e25ab5c61348d090bf1b07f1953929c13bd2309a0662e9ff680763c9"}, + {file = "regex-2023.12.25-cp39-cp39-win_amd64.whl", hash = "sha256:e693e233ac92ba83a87024e1d32b5f9ab15ca55ddd916d878146f4e3406b5c91"}, + {file = "regex-2023.12.25.tar.gz", hash = "sha256:29171aa128da69afdf4bde412d5bedc335f2ca8fcfe4489038577d05f16181e5"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rlp" +version = "4.0.0" +description = "rlp: A package for Recursive Length Prefix encoding and decoding" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "rlp-4.0.0-py3-none-any.whl", hash = "sha256:1747fd933e054e6d25abfe591be92e19a4193a56c93981c05bd0f84dfe279f14"}, + {file = "rlp-4.0.0.tar.gz", hash = "sha256:61a5541f86e4684ab145cb849a5929d2ced8222930a570b3941cf4af16b72a78"}, +] + +[package.dependencies] +eth-utils = ">=2" + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "hypothesis (==5.19.0)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +rust-backend = ["rusty-rlp (>=0.2.1,<0.3)"] +test = ["hypothesis (==5.19.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "rpds-py" +version = "0.16.2" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rpds_py-0.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:509b617ac787cd1149600e731db9274ebbef094503ca25158e6f23edaba1ca8f"}, + {file = "rpds_py-0.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:413b9c17388bbd0d87a329d8e30c1a4c6e44e2bb25457f43725a8e6fe4161e9e"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2946b120718eba9af2b4dd103affc1164a87b9e9ebff8c3e4c05d7b7a7e274e2"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:35ae5ece284cf36464eb160880018cf6088a9ac5ddc72292a6092b6ef3f4da53"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc6a7620ba7639a3db6213da61312cb4aa9ac0ca6e00dc1cbbdc21c2aa6eb57"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8cb6fe8ecdfffa0e711a75c931fb39f4ba382b4b3ccedeca43f18693864fe850"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dace7b26a13353e24613417ce2239491b40a6ad44e5776a18eaff7733488b44"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1bdbc5fcb04a7309074de6b67fa9bc4b418ab3fc435fec1f2779a0eced688d04"}, + {file = "rpds_py-0.16.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f42e25c016927e2a6b1ce748112c3ab134261fc2ddc867e92d02006103e1b1b7"}, + {file = "rpds_py-0.16.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eab36eae3f3e8e24b05748ec9acc66286662f5d25c52ad70cadab544e034536b"}, + {file = "rpds_py-0.16.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0474df4ade9a3b4af96c3d36eb81856cb9462e4c6657d4caecfd840d2a13f3c9"}, + {file = "rpds_py-0.16.2-cp310-none-win32.whl", hash = "sha256:84c5a4d1f9dd7e2d2c44097fb09fffe728629bad31eb56caf97719e55575aa82"}, + {file = "rpds_py-0.16.2-cp310-none-win_amd64.whl", hash = "sha256:2bd82db36cd70b3628c0c57d81d2438e8dd4b7b32a6a9f25f24ab0e657cb6c4e"}, + {file = "rpds_py-0.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:adc0c3d6fc6ae35fee3e4917628983f6ce630d513cbaad575b4517d47e81b4bb"}, + {file = "rpds_py-0.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ec23fcad480e77ede06cf4127a25fc440f7489922e17fc058f426b5256ee0edb"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07aab64e2808c3ebac2a44f67e9dc0543812b715126dfd6fe4264df527556cb6"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a4ebb8b20bd09c5ce7884c8f0388801100f5e75e7f733b1b6613c713371feefc"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3d7e2ea25d3517c6d7e5a1cc3702cffa6bd18d9ef8d08d9af6717fc1c700eed"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f28ac0e8e7242d140f99402a903a2c596ab71550272ae9247ad78f9a932b5698"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19f00f57fdd38db4bb5ad09f9ead1b535332dbf624200e9029a45f1f35527ebb"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3da5a4c56953bdbf6d04447c3410309616c54433146ccdb4a277b9cb499bc10e"}, + {file = "rpds_py-0.16.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec2e1cf025b2c0f48ec17ff3e642661da7ee332d326f2e6619366ce8e221f018"}, + {file = "rpds_py-0.16.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e0441fb4fdd39a230477b2ca9be90868af64425bfe7b122b57e61e45737a653b"}, + {file = "rpds_py-0.16.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9f0350ef2fba5f34eb0c9000ea328e51b9572b403d2f7f3b19f24085f6f598e8"}, + {file = "rpds_py-0.16.2-cp311-none-win32.whl", hash = "sha256:5a80e2f83391ad0808b4646732af2a7b67550b98f0cae056cb3b40622a83dbb3"}, + {file = "rpds_py-0.16.2-cp311-none-win_amd64.whl", hash = "sha256:e04e56b4ca7a770593633556e8e9e46579d66ec2ada846b401252a2bdcf70a6d"}, + {file = "rpds_py-0.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:5e6caa3809e50690bd92fa490f5c38caa86082c8c3315aa438bce43786d5e90d"}, + {file = "rpds_py-0.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e53b9b25cac9065328901713a7e9e3b12e4f57ef4280b370fbbf6fef2052eef"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af27423662f32d7501a00c5e7342f7dbd1e4a718aea7a239781357d15d437133"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43d4dd5fb16eb3825742bad8339d454054261ab59fed2fbac84e1d84d5aae7ba"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e061de3b745fe611e23cd7318aec2c8b0e4153939c25c9202a5811ca911fd733"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b811d182ad17ea294f2ec63c0621e7be92a1141e1012383461872cead87468f"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5552f328eaef1a75ff129d4d0c437bf44e43f9436d3996e8eab623ea0f5fcf73"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dcbe1f8dd179e4d69b70b1f1d9bb6fd1e7e1bdc9c9aad345cdeb332e29d40748"}, + {file = "rpds_py-0.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8aad80645a011abae487d356e0ceb359f4938dfb6f7bcc410027ed7ae4f7bb8b"}, + {file = "rpds_py-0.16.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b6f5549d6ed1da9bfe3631ca9483ae906f21410be2445b73443fa9f017601c6f"}, + {file = "rpds_py-0.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d452817e0d9c749c431a1121d56a777bd7099b720b3d1c820f1725cb40928f58"}, + {file = "rpds_py-0.16.2-cp312-none-win32.whl", hash = "sha256:888a97002e986eca10d8546e3c8b97da1d47ad8b69726dcfeb3e56348ebb28a3"}, + {file = "rpds_py-0.16.2-cp312-none-win_amd64.whl", hash = "sha256:d8dda2a806dfa4a9b795950c4f5cc56d6d6159f7d68080aedaff3bdc9b5032f5"}, + {file = "rpds_py-0.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:071980663c273bf3d388fe5c794c547e6f35ba3335477072c713a3176bf14a60"}, + {file = "rpds_py-0.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:726ac36e8a3bb8daef2fd482534cabc5e17334052447008405daca7ca04a3108"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9e557db6a177470316c82f023e5d571811c9a4422b5ea084c85da9aa3c035fc"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:90123853fc8b1747f80b0d354be3d122b4365a93e50fc3aacc9fb4c2488845d6"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a61f659665a39a4d17d699ab3593d7116d66e1e2e3f03ef3fb8f484e91908808"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc97f0640e91d7776530f06e6836c546c1c752a52de158720c4224c9e8053cad"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44a54e99a2b9693a37ebf245937fd6e9228b4cbd64b9cc961e1f3391ec6c7391"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd4b677d929cf1f6bac07ad76e0f2d5de367e6373351c01a9c0a39f6b21b4a8b"}, + {file = "rpds_py-0.16.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5ef00873303d678aaf8b0627e111fd434925ca01c657dbb2641410f1cdaef261"}, + {file = "rpds_py-0.16.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:349cb40897fd529ca15317c22c0eab67f5ac5178b5bd2c6adc86172045210acc"}, + {file = "rpds_py-0.16.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2ddef620e70eaffebed5932ce754d539c0930f676aae6212f8e16cd9743dd365"}, + {file = "rpds_py-0.16.2-cp38-none-win32.whl", hash = "sha256:882ce6e25e585949c3d9f9abd29202367175e0aab3aba0c58c9abbb37d4982ff"}, + {file = "rpds_py-0.16.2-cp38-none-win_amd64.whl", hash = "sha256:f4bd4578e44f26997e9e56c96dedc5f1af43cc9d16c4daa29c771a00b2a26851"}, + {file = "rpds_py-0.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:69ac7ea9897ec201ce68b48582f3eb34a3f9924488a5432a93f177bf76a82a7e"}, + {file = "rpds_py-0.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a9880b4656efe36ccad41edc66789e191e5ee19a1ea8811e0aed6f69851a82f4"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee94cb58c0ba2c62ee108c2b7c9131b2c66a29e82746e8fa3aa1a1effbd3dcf1"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24f7a2eb3866a9e91f4599851e0c8d39878a470044875c49bd528d2b9b88361c"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca57468da2d9a660bcf8961637c85f2fbb2aa64d9bc3f9484e30c3f9f67b1dd7"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ccd4e400309e1f34a5095bf9249d371f0fd60f8a3a5c4a791cad7b99ce1fd38d"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80443fe2f7b3ea3934c5d75fb0e04a5dbb4a8e943e5ff2de0dec059202b70a8b"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4d6a9f052e72d493efd92a77f861e45bab2f6be63e37fa8ecf0c6fd1a58fedb0"}, + {file = "rpds_py-0.16.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:35953f4f2b3216421af86fd236b7c0c65935936a94ea83ddbd4904ba60757773"}, + {file = "rpds_py-0.16.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:981d135c7cdaf6cd8eadae1c950de43b976de8f09d8e800feed307140d3d6d00"}, + {file = "rpds_py-0.16.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d0dd7ed2f16df2e129496e7fbe59a34bc2d7fc8db443a606644d069eb69cbd45"}, + {file = "rpds_py-0.16.2-cp39-none-win32.whl", hash = "sha256:703d95c75a72e902544fda08e965885525e297578317989fd15a6ce58414b41d"}, + {file = "rpds_py-0.16.2-cp39-none-win_amd64.whl", hash = "sha256:e93ec1b300acf89730cf27975ef574396bc04edecc358e9bd116fb387a123239"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:44627b6ca7308680a70766454db5249105fa6344853af6762eaad4158a2feebe"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:3f91df8e6dbb7360e176d1affd5fb0246d2b88d16aa5ebc7db94fd66b68b61da"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d904c5693e08bad240f16d79305edba78276be87061c872a4a15e2c301fa2c0"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:290a81cfbe4673285cdf140ec5cd1658ffbf63ab359f2b352ebe172e7cfa5bf0"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b634c5ec0103c5cbebc24ebac4872b045cccb9456fc59efdcf6fe39775365bd2"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a297a4d08cc67c7466c873c78039d87840fb50d05473db0ec1b7b03d179bf322"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2e75e17bd0bb66ee34a707da677e47c14ee51ccef78ed6a263a4cc965a072a1"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f1b9d9260e06ea017feb7172976ab261e011c1dc2f8883c7c274f6b2aabfe01a"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:162d7cd9cd311c1b0ff1c55a024b8f38bd8aad1876b648821da08adc40e95734"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:9b32f742ce5b57201305f19c2ef7a184b52f6f9ba6871cc042c2a61f0d6b49b8"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac08472f41ea77cd6a5dae36ae7d4ed3951d6602833af87532b556c1b4601d63"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:495a14b72bbe217f2695dcd9b5ab14d4f8066a00f5d209ed94f0aca307f85f6e"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:8d6b6937ae9eac6d6c0ca3c42774d89fa311f55adff3970fb364b34abde6ed3d"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a61226465bda9283686db8f17d02569a98e4b13c637be5a26d44aa1f1e361c2"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5cf6af100ffb5c195beec11ffaa8cf8523057f123afa2944e6571d54da84cdc9"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6df15846ee3fb2e6397fe25d7ca6624af9f89587f3f259d177b556fed6bebe2c"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1be2f033df1b8be8c3167ba3c29d5dca425592ee31e35eac52050623afba5772"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96f957d6ab25a78b9e7fc9749d754b98eac825a112b4e666525ce89afcbd9ed5"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:088396c7c70e59872f67462fcac3ecbded5233385797021976a09ebd55961dfe"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4c46ad6356e1561f2a54f08367d1d2e70a0a1bb2db2282d2c1972c1d38eafc3b"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:47713dc4fce213f5c74ca8a1f6a59b622fc1b90868deb8e8e4d993e421b4b39d"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:f811771019f063bbd0aa7bb72c8a934bc13ebacb4672d712fc1639cfd314cccc"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f19afcfc0dd0dca35694df441e9b0f95bc231b512f51bded3c3d8ca32153ec19"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a4b682c5775d6a3d21e314c10124599976809455ee67020e8e72df1769b87bc3"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c647ca87fc0ebe808a41de912e9a1bfef9acb85257e5d63691364ac16b81c1f0"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:302bd4983bbd47063e452c38be66153760112f6d3635c7eeefc094299fa400a9"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bf721ede3eb7b829e4a9b8142bd55db0bdc82902720548a703f7e601ee13bdc3"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:358dafc89ce3894c7f486c615ba914609f38277ef67f566abc4c854d23b997fa"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cad0f59ee3dc35526039f4bc23642d52d5f6616b5f687d846bfc6d0d6d486db0"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cffa76b385dfe1e38527662a302b19ffb0e7f5cf7dd5e89186d2c94a22dd9d0c"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:83640a5d7cd3bff694747d50436b8b541b5b9b9782b0c8c1688931d6ee1a1f2d"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:ed99b4f7179d2111702020fd7d156e88acd533f5a7d3971353e568b6051d5c97"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4022b9dc620e14f30201a8a73898a873c8e910cb642bcd2f3411123bc527f6ac"}, + {file = "rpds_py-0.16.2.tar.gz", hash = "sha256:781ef8bfc091b19960fc0142a23aedadafa826bc32b433fdfe6fd7f964d7ef44"}, +] + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[[package]] +name = "toolz" +version = "0.12.0" +description = "List processing tools and functional utilities" +optional = false +python-versions = ">=3.5" +files = [ + {file = "toolz-0.12.0-py3-none-any.whl", hash = "sha256:2059bd4148deb1884bb0eb770a3cde70e7f954cfbbdc2285f1f2de01fd21eb6f"}, + {file = "toolz-0.12.0.tar.gz", hash = "sha256:88c570861c440ee3f2f6037c4654613228ff40c93a6c25e0eba70d17282c6194"}, +] + +[[package]] +name = "typing-extensions" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, +] + +[[package]] +name = "urllib3" +version = "2.1.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, + {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "web3" +version = "6.14.0" +description = "web3.py" +optional = false +python-versions = ">=3.7.2" +files = [ + {file = "web3-6.14.0-py3-none-any.whl", hash = "sha256:e7023669ea05d6c9675d25e14342638da25d9b1a512d8a6472b860ed97914aec"}, + {file = "web3-6.14.0.tar.gz", hash = "sha256:a3726289da9eff2ce30f9b1b49ec59e9245216f7aecbfa2007f73dbe94999717"}, +] + +[package.dependencies] +aiohttp = ">=3.7.4.post0" +eth-abi = ">=4.0.0" +eth-account = ">=0.8.0" +eth-hash = {version = ">=0.5.1", extras = ["pycryptodome"]} +eth-typing = ">=3.0.0" +eth-utils = ">=2.1.0" +hexbytes = ">=0.1.0,<0.4.0" +jsonschema = ">=4.0.0" +lru-dict = ">=1.1.6,<1.3.0" +protobuf = ">=4.21.6" +pyunormalize = ">=15.0.0" +pywin32 = {version = ">=223", markers = "platform_system == \"Windows\""} +requests = ">=2.16.0" +typing-extensions = ">=4.0.1" +websockets = ">=10.0.0" + +[package.extras] +dev = ["black (>=22.1.0)", "build (>=0.9.0)", "bumpversion", "eth-tester[py-evm] (==v0.9.1-b.1)", "flake8 (==3.8.3)", "flaky (>=3.7.0)", "hypothesis (>=3.31.2)", "importlib-metadata (<5.0)", "ipfshttpclient (==0.8.0a2)", "isort (>=5.11.0)", "mypy (==1.4.1)", "py-geth (>=3.11.0)", "pytest (>=7.0.0)", "pytest-asyncio (>=0.18.1,<0.23)", "pytest-mock (>=1.10)", "pytest-watch (>=4.2)", "pytest-xdist (>=1.29)", "setuptools (>=38.6.0)", "sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=3.18.0)", "tqdm (>4.32)", "twine (>=1.13)", "types-protobuf (==3.19.13)", "types-requests (>=2.26.1)", "types-setuptools (>=57.4.4)", "when-changed (>=0.3.0)"] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +ipfs = ["ipfshttpclient (==0.8.0a2)"] +linter = ["black (>=22.1.0)", "flake8 (==3.8.3)", "isort (>=5.11.0)", "mypy (==1.4.1)", "types-protobuf (==3.19.13)", "types-requests (>=2.26.1)", "types-setuptools (>=57.4.4)"] +tester = ["eth-tester[py-evm] (==v0.9.1-b.1)", "py-geth (>=3.11.0)"] + +[[package]] +name = "websockets" +version = "12.0" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"}, + {file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"}, + {file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"}, + {file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"}, + {file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"}, + {file = "websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480"}, + {file = "websockets-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"}, + {file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"}, + {file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"}, + {file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"}, + {file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"}, + {file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"}, + {file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"}, + {file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"}, + {file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"}, + {file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"}, + {file = "websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04"}, + {file = "websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"}, + {file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"}, + {file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"}, + {file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"}, + {file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"}, + {file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"}, + {file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"}, + {file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"}, + {file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"}, + {file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"}, + {file = "websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed"}, + {file = "websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"}, + {file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"}, + {file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"}, + {file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"}, + {file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"}, + {file = "websockets-12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5f6ffe2c6598f7f7207eef9a1228b6f5c818f9f4d53ee920aacd35cec8110438"}, + {file = "websockets-12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9edf3fc590cc2ec20dc9d7a45108b5bbaf21c0d89f9fd3fd1685e223771dc0b2"}, + {file = "websockets-12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8572132c7be52632201a35f5e08348137f658e5ffd21f51f94572ca6c05ea81d"}, + {file = "websockets-12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604428d1b87edbf02b233e2c207d7d528460fa978f9e391bd8aaf9c8311de137"}, + {file = "websockets-12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a9d160fd080c6285e202327aba140fc9a0d910b09e423afff4ae5cbbf1c7205"}, + {file = "websockets-12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b4aafed34653e465eb77b7c93ef058516cb5acf3eb21e42f33928616172def"}, + {file = "websockets-12.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b2ee7288b85959797970114deae81ab41b731f19ebcd3bd499ae9ca0e3f1d2c8"}, + {file = "websockets-12.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7fa3d25e81bfe6a89718e9791128398a50dec6d57faf23770787ff441d851967"}, + {file = "websockets-12.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a571f035a47212288e3b3519944f6bf4ac7bc7553243e41eac50dd48552b6df7"}, + {file = "websockets-12.0-cp38-cp38-win32.whl", hash = "sha256:3c6cc1360c10c17463aadd29dd3af332d4a1adaa8796f6b0e9f9df1fdb0bad62"}, + {file = "websockets-12.0-cp38-cp38-win_amd64.whl", hash = "sha256:1bf386089178ea69d720f8db6199a0504a406209a0fc23e603b27b300fdd6892"}, + {file = "websockets-12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab3d732ad50a4fbd04a4490ef08acd0517b6ae6b77eb967251f4c263011a990d"}, + {file = "websockets-12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1d9697f3337a89691e3bd8dc56dea45a6f6d975f92e7d5f773bc715c15dde28"}, + {file = "websockets-12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1df2fbd2c8a98d38a66f5238484405b8d1d16f929bb7a33ed73e4801222a6f53"}, + {file = "websockets-12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23509452b3bc38e3a057382c2e941d5ac2e01e251acce7adc74011d7d8de434c"}, + {file = "websockets-12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e5fc14ec6ea568200ea4ef46545073da81900a2b67b3e666f04adf53ad452ec"}, + {file = "websockets-12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46e71dbbd12850224243f5d2aeec90f0aaa0f2dde5aeeb8fc8df21e04d99eff9"}, + {file = "websockets-12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b81f90dcc6c85a9b7f29873beb56c94c85d6f0dac2ea8b60d995bd18bf3e2aae"}, + {file = "websockets-12.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a02413bc474feda2849c59ed2dfb2cddb4cd3d2f03a2fedec51d6e959d9b608b"}, + {file = "websockets-12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bbe6013f9f791944ed31ca08b077e26249309639313fff132bfbf3ba105673b9"}, + {file = "websockets-12.0-cp39-cp39-win32.whl", hash = "sha256:cbe83a6bbdf207ff0541de01e11904827540aa069293696dd528a6640bd6a5f6"}, + {file = "websockets-12.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc4e7fa5414512b481a2483775a8e8be7803a35b30ca805afa4998a84f9fd9e8"}, + {file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"}, + {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"}, + {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077"}, + {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b"}, + {file = "websockets-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"}, + {file = "websockets-12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6"}, + {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123"}, + {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931"}, + {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2"}, + {file = "websockets-12.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468"}, + {file = "websockets-12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b"}, + {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399"}, + {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7"}, + {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611"}, + {file = "websockets-12.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370"}, + {file = "websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e"}, + {file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"}, +] + +[[package]] +name = "yarl" +version = "1.9.4" +description = "Yet another URL library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, + {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, + {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, + {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, + {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, + {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, + {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, + {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, + {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, + {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, + {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, + {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, + {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, + {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, + {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, + {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" + +[metadata] +lock-version = "2.0" +python-versions = "^3.11" +content-hash = "1a7885b0edfbf381ad97ee7a1d807331f2dafc7fdbf40cb6179e97b26c234936" diff --git a/beacon/protocols/beacon_token_vault.py b/per_sdk/protocols/beacon_token_vault.py similarity index 93% rename from beacon/protocols/beacon_token_vault.py rename to per_sdk/protocols/beacon_token_vault.py index 5e5c3a41..a50d3581 100644 --- a/beacon/protocols/beacon_token_vault.py +++ b/per_sdk/protocols/beacon_token_vault.py @@ -1,15 +1,15 @@ +import argparse +import asyncio import base64 -import web3 -from eth_abi import encode import json -from typing import TypedDict -import argparse import logging -import asyncio -import httpx +from typing import TypedDict -from beacon.utils.pyth_prices import PriceFeedClient, PriceFeed +import httpx +import web3 +from beacon.utils.pyth_prices import PriceFeed, PriceFeedClient from beacon.utils.types_liquidation_adapter import LiquidationOpportunity +from eth_abi import encode class ProtocolAccount(TypedDict): @@ -147,8 +147,7 @@ def create_liquidation_opp( "value": str(call_value), "repay_tokens": repay_tokens, "receipt_tokens": [ - (account["token_address_collateral"], - str(account["amount_collateral"])) + (account["token_address_collateral"], str(account["amount_collateral"])) ], } @@ -160,7 +159,7 @@ def create_liquidation_opp( return opp - async def get_liquidation_opportunities(self) -> (list[LiquidationOpportunity]): + async def get_liquidation_opportunities(self) -> list[LiquidationOpportunity]: """ Filters list of ProtocolAccount types to return a list of LiquidationOpportunity types. @@ -195,19 +194,16 @@ async def get_liquidation_opportunities(self) -> (list[LiquidationOpportunity]): ) value_collateral = ( - int(price_collateral["price"]["price"]) * - account["amount_collateral"] + int(price_collateral["price"]["price"]) * account["amount_collateral"] ) - value_debt = int(price_debt["price"] - ["price"]) * account["amount_debt"] + value_debt = int(price_debt["price"]["price"]) * account["amount_debt"] print(account["account_number"], value_collateral / value_debt) if ( value_debt * int(account["min_health_ratio"]) > value_collateral * 10**18 ): price_updates = [price_collateral, price_debt] - liquidatable.append( - self.create_liquidation_opp(account, price_updates)) + liquidatable.append(self.create_liquidation_opp(account, price_updates)) return liquidatable @@ -251,8 +247,7 @@ async def main(): logging.basicConfig(level=logging.INFO) logging.getLogger("httpx").propagate = False - monitor = VaultMonitor( - args.rpc_url, args.vault_contract, args.weth_contract) + monitor = VaultMonitor(args.rpc_url, args.vault_contract, args.weth_contract) while True: opportunities = await monitor.get_liquidation_opportunities() diff --git a/per_sdk/pyproject.toml b/per_sdk/pyproject.toml new file mode 100644 index 00000000..243596b4 --- /dev/null +++ b/per_sdk/pyproject.toml @@ -0,0 +1,62 @@ +[tool.poetry] +name = "per-sdk" +version = "0.1.0" +description = "Python SDK for interacting with Pyth Express Relay" +authors = [] +license = "Apache-2" +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.11" +aiohttp = "3.9.1" +aiosignal = "1.3.1" +anyio = "4.2.0" +attrs = "23.2.0" +bitarray = "2.9.2" +certifi = "2023.11.17" +charset-normalizer = "3.3.2" +cytoolz = "0.12.2" +eth-account = "0.10.0" +eth-hash = "0.6.0" +eth-keyfile = "0.7.0" +eth-keys = "0.5.0" +eth-rlp = "1.0.0" +eth-typing = "4.0.0" +eth-utils = "3.0.0" +eth-abi = "5.0.0" +frozenlist = "1.4.1" +h11 = "0.14.0" +hexbytes = "0.3.1" +httpcore = "1.0.2" +httpx = "0.26.0" +idna = "3.6" +jsonschema = "4.20.0" +jsonschema-specifications = "2023.12.1" +lru-dict = "1.2.0" +multidict = "6.0.4" +parsimonious = "0.9.0" +protobuf = "4.25.2" +pycryptodome = "3.20.0" +pyunormalize = "15.1.0" +referencing = "0.32.1" +regex = "2023.12.25" +requests = "2.31.0" +rlp = "4.0.0" +rpds-py = "0.16.2" +sniffio = "1.3.0" +toolz = "0.12.0" +typing-extensions = "4.9.0" +urllib3 = "2.1.0" +web3 = "6.14.0" +websockets = "12.0" +yarl = "1.9.4" + + +[tool.poetry.group.dev.dependencies] +black = "^24.1.1" +pyflakes = "^3.2.0" +isort = "^5.13.2" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/beacon/searcher/searcher_template.py b/per_sdk/searcher/searcher_template.py similarity index 100% rename from beacon/searcher/searcher_template.py rename to per_sdk/searcher/searcher_template.py diff --git a/beacon/searcher/searcher_utils.py b/per_sdk/searcher/searcher_utils.py similarity index 78% rename from beacon/searcher/searcher_utils.py rename to per_sdk/searcher/searcher_utils.py index 8e94c76e..109f5b32 100644 --- a/beacon/searcher/searcher_utils.py +++ b/per_sdk/searcher/searcher_utils.py @@ -1,7 +1,8 @@ +from typing import TypedDict + import web3 -from web3.auto import w3 from eth_abi import encode -from typing import TypedDict +from web3.auto import w3 class UserLiquidationParams(TypedDict): @@ -17,7 +18,7 @@ def construct_signature_liquidator( value: int, bid: int, valid_until: int, - secret_key: str + secret_key: str, ): """ Constructs a signature for a liquidator's transaction to submit to the LiquidationAdapter contract. @@ -36,13 +37,17 @@ def construct_signature_liquidator( """ digest = encode( - ['(address,uint256)[]', '(address,uint256)[]', - 'address', 'bytes', 'uint256', 'uint256'], - [repay_tokens, receipt_tokens, address, liq_calldata, value, bid] + [ + "(address,uint256)[]", + "(address,uint256)[]", + "address", + "bytes", + "uint256", + "uint256", + ], + [repay_tokens, receipt_tokens, address, liq_calldata, value, bid], ) - msg_data = web3.Web3.solidity_keccak( - ['bytes', 'uint256'], [digest, valid_until]) - signature = w3.eth.account.signHash( - msg_data, private_key=secret_key) + msg_data = web3.Web3.solidity_keccak(["bytes", "uint256"], [digest, valid_until]) + signature = w3.eth.account.signHash(msg_data, private_key=secret_key) return signature diff --git a/beacon/searcher/simple_searcher.py b/per_sdk/searcher/simple_searcher.py similarity index 54% rename from beacon/searcher/simple_searcher.py rename to per_sdk/searcher/simple_searcher.py index 0c2b95f5..7699c5d7 100644 --- a/beacon/searcher/simple_searcher.py +++ b/per_sdk/searcher/simple_searcher.py @@ -1,25 +1,31 @@ -from eth_account import Account -from eth_account.signers.local import LocalAccount -from eth_abi import encode -import httpx -import logging -import asyncio import argparse +import asyncio +import logging +from typing import TypedDict -from beacon.utils.types_liquidation_adapter import * -from beacon.utils.endpoints import BEACON_SERVER_ENDPOINT_GETOPPS, BEACON_SERVER_ENDPOINT_BID -from beacon.searcher.searcher_utils import UserLiquidationParams, construct_signature_liquidator +import httpx +from beacon.searcher.searcher_utils import ( + UserLiquidationParams, + construct_signature_liquidator, +) +from beacon.utils.endpoints import ( + BEACON_SERVER_ENDPOINT_BID, + BEACON_SERVER_ENDPOINT_GETOPPS, +) +from beacon.utils.types_liquidation_adapter import LiquidationOpportunity +from eth_account import Account +from eth_account.signers.local import LocalAccount BID = 10 VALID_UNTIL = 1_000_000_000_000 def assess_liquidation_opportunity( - opp: LiquidationOpportunity + opp: LiquidationOpportunity, ) -> UserLiquidationParams | None: user_liquidation_params: UserLiquidationParams = { "bid": BID, - "valid_until": VALID_UNTIL + "valid_until": VALID_UNTIL, } return user_liquidation_params @@ -34,42 +40,38 @@ class OpportunityBid(TypedDict): def create_liquidation_transaction( - opp: LiquidationOpportunity, - sk_liquidator: str, - valid_until: int, - bid: int + opp: LiquidationOpportunity, sk_liquidator: str, valid_until: int, bid: int ) -> OpportunityBid: - repay_tokens = [(opp['contract'], int(opp['amount'])) - for opp in opp['repay_tokens']] - receipt_tokens = [(opp['contract'], int(opp['amount'])) - for opp in opp['receipt_tokens']] + repay_tokens = [ + (opp["contract"], int(opp["amount"])) for opp in opp["repay_tokens"] + ] + receipt_tokens = [ + (opp["contract"], int(opp["amount"])) for opp in opp["receipt_tokens"] + ] account: LocalAccount = Account.from_key(sk_liquidator) liquidator = account.address - liq_calldata = bytes.fromhex(opp['calldata'].replace('0x', '')) + liq_calldata = bytes.fromhex(opp["calldata"].replace("0x", "")) signature_liquidator = construct_signature_liquidator( - repay_tokens, receipt_tokens, opp['contract'], liq_calldata, int(opp['value']), bid, valid_until, sk_liquidator) - - liquidation_adapter_calldata: LiquidationAdapterCalldata = { - "repay_tokens": repay_tokens, - "expected_receipt_tokens": receipt_tokens, - "liquidator": liquidator, - "contract": opp['contract'], - "data": liq_calldata, - "valid_until": valid_until, - "bid": bid, - "signature_liquidator": bytes(signature_liquidator.signature) - } + repay_tokens, + receipt_tokens, + opp["contract"], + liq_calldata, + int(opp["value"]), + bid, + valid_until, + sk_liquidator, + ) - json_body: OpportunityBid = { - "chain_id": opp['chain_id'], - "opportunity_id": opp['opportunity_id'], - "permission_key": opp['permission_key'], + json_body = { + "chain_id": opp["chain_id"], + "opportunity_id": opp["opportunity_id"], + "permission_key": opp["permission_key"], "bid_amount": str(bid), "valid_until": str(valid_until), "liquidator": liquidator, - "signature": bytes(signature_liquidator.signature).hex() + "signature": bytes(signature_liquidator.signature).hex(), } return json_body @@ -98,25 +100,28 @@ async def main(): sk_liquidator = args.private_key client = httpx.AsyncClient() while True: - accounts_liquidatable = (await client.get(BEACON_SERVER_ENDPOINT_GETOPPS, params=params)).json() + accounts_liquidatable = ( + await client.get(BEACON_SERVER_ENDPOINT_GETOPPS, params=params) + ).json() for liquidation_opp in accounts_liquidatable: - user_liquidation_params = assess_liquidation_opportunity( - liquidation_opp) + user_liquidation_params = assess_liquidation_opportunity(liquidation_opp) if user_liquidation_params is not None: - bid, valid_until = user_liquidation_params["bid"], user_liquidation_params["valid_until"] + bid, valid_until = ( + user_liquidation_params["bid"], + user_liquidation_params["valid_until"], + ) tx = create_liquidation_transaction( - liquidation_opp, sk_liquidator, valid_until, bid) - - resp = await client.post( - BEACON_SERVER_ENDPOINT_BID, - json=tx + liquidation_opp, sk_liquidator, valid_until, bid ) + resp = await client.post(BEACON_SERVER_ENDPOINT_BID, json=tx) + print(resp.text) await asyncio.sleep(5) + if __name__ == "__main__": asyncio.run(main()) diff --git a/per_sdk/utils/endpoints.py b/per_sdk/utils/endpoints.py new file mode 100644 index 00000000..5c6aa67c --- /dev/null +++ b/per_sdk/utils/endpoints.py @@ -0,0 +1,10 @@ +BEACON_SERVER_ENDPOINT = "http://localhost:9000" +AUCTION_SERVER_ENDPOINT = "http://localhost:9000/bid" + +BEACON_SERVER_ENDPOINT_SURFACE = ( + f"{BEACON_SERVER_ENDPOINT}/liquidation/submit_opportunity" +) +BEACON_SERVER_ENDPOINT_GETOPPS = ( + f"{BEACON_SERVER_ENDPOINT}/liquidation/fetch_opportunities" +) +BEACON_SERVER_ENDPOINT_BID = f"{BEACON_SERVER_ENDPOINT}/liquidation/bid_opportunity" diff --git a/beacon/utils/pyth_prices.py b/per_sdk/utils/pyth_prices.py similarity index 88% rename from beacon/utils/pyth_prices.py rename to per_sdk/utils/pyth_prices.py index c159666f..92da18c2 100644 --- a/beacon/utils/pyth_prices.py +++ b/per_sdk/utils/pyth_prices.py @@ -1,7 +1,8 @@ -import httpx import asyncio from typing import TypedDict +import httpx + HERMES_ENDPOINT_HTTPS = "https://hermes.pyth.network/api/" HERMES_ENDPOINT_WSS = "wss://hermes.pyth.network/ws" @@ -49,21 +50,18 @@ def extract_price_feed(self, data: dict) -> PriceFeed: """ Extracts a PriceFeed object from the JSON response from Hermes. """ - price = data['price'] - price_ema = data['ema_price'] - vaa = data['vaa'] + price = data["price"] + price_ema = data["ema_price"] + vaa = data["vaa"] price_feed = { - "feed_id": data['id'], + "feed_id": data["id"], "price": price, "price_ema": price_ema, - "vaa": vaa + "vaa": vaa, } return price_feed - async def get_pyth_prices_latest( - self, - feedIds: list[str] - ) -> list[PriceFeed]: + async def get_pyth_prices_latest(self, feedIds: list[str]) -> list[PriceFeed]: """ Queries the Hermes https endpoint for the latest price feeds for a list of Pyth feed IDs. """ @@ -79,15 +77,11 @@ async def get_pyth_prices_latest( return results - async def get_pyth_price_at_time( - self, - feed_id: str, - timestamp: int - ) -> PriceFeed: + async def get_pyth_price_at_time(self, feed_id: str, timestamp: int) -> PriceFeed: """ Queries the Hermes https endpoint for the price feed for a Pyth feed ID at a given timestamp. """ - url = HERMES_ENDPOINT_HTTPS + f"get_price_feed" + url = HERMES_ENDPOINT_HTTPS + "get_price_feed" params = {"id": feed_id, "publish_time": timestamp, "binary": "true"} data = (await self.client.get(url, params=params)).json() @@ -105,8 +99,10 @@ async def get_all_prices(self) -> dict[str, PriceFeed]: pyth_prices_latest = [] i = 0 batch_size = 100 - while len(self.feed_ids[i:i + batch_size]) > 0: - pyth_prices_latest += await self.get_pyth_prices_latest(self.feed_ids[i:i + batch_size]) + while len(self.feed_ids[i : i + batch_size]) > 0: + pyth_prices_latest += await self.get_pyth_prices_latest( + self.feed_ids[i : i + batch_size] + ) i += batch_size return dict(pyth_prices_latest) @@ -116,6 +112,7 @@ async def ws_pyth_prices(self): Opens a websocket connection to Hermes for latest prices for all feed IDs in the class object. """ import json + import websockets async with websockets.connect(HERMES_ENDPOINT_WSS) as ws: @@ -125,7 +122,7 @@ async def ws_pyth_prices(self): "ids": self.pending_feed_ids, "type": "subscribe", "verbose": True, - "binary": True + "binary": True, } await ws.send(json.dumps(json_subscribe)) self.pending_feed_ids = [] @@ -160,5 +157,6 @@ async def main(): while True: await asyncio.sleep(1) + if __name__ == "__main__": asyncio.run(main()) diff --git a/beacon/utils/types_liquidation_adapter.py b/per_sdk/utils/types_liquidation_adapter.py similarity index 100% rename from beacon/utils/types_liquidation_adapter.py rename to per_sdk/utils/types_liquidation_adapter.py From de0a858ee66f23cc739a3c9ff1011f0a833d1044 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 16:20:04 +0100 Subject: [PATCH 18/41] Rename beacon server to liquidation server --- ..._token_vault.py => token_vault_monitor.py} | 21 ++++++++++--------- per_sdk/searcher/simple_searcher.py | 19 +++++++++-------- per_sdk/utils/endpoints.py | 14 +++++++------ 3 files changed, 29 insertions(+), 25 deletions(-) rename per_sdk/protocols/{beacon_token_vault.py => token_vault_monitor.py} (93%) diff --git a/per_sdk/protocols/beacon_token_vault.py b/per_sdk/protocols/token_vault_monitor.py similarity index 93% rename from per_sdk/protocols/beacon_token_vault.py rename to per_sdk/protocols/token_vault_monitor.py index a50d3581..30cc15aa 100644 --- a/per_sdk/protocols/beacon_token_vault.py +++ b/per_sdk/protocols/token_vault_monitor.py @@ -7,10 +7,11 @@ import httpx import web3 -from beacon.utils.pyth_prices import PriceFeed, PriceFeedClient -from beacon.utils.types_liquidation_adapter import LiquidationOpportunity from eth_abi import encode +from per_sdk.utils.pyth_prices import PriceFeed, PriceFeedClient +from per_sdk.utils.types_liquidation_adapter import LiquidationOpportunity + class ProtocolAccount(TypedDict): """ @@ -234,13 +235,13 @@ async def main(): group.add_argument( "--dry-run", action="store_false", - dest="send_beacon", - help="If provided, will not send liquidation opportunities to the beacon server", + dest="broadcast", + help="If provided, will not send liquidation opportunities to the server", ) group.add_argument( - "--beacon-server-url", + "--liquidation-server-url", type=str, - help="Beacon server endpoint; if provided, will send liquidation opportunities to the beacon server", + help="Liquidation server endpoint; if provided, will send liquidation opportunities to this endpoint", ) args = parser.parse_args() @@ -252,15 +253,15 @@ async def main(): while True: opportunities = await monitor.get_liquidation_opportunities() - if args.send_beacon: + if args.broadcast: client = httpx.AsyncClient() for opp in opportunities: - resp = await client.post(args.beacon_server_url, json=opp) + resp = await client.post(args.liquidation_server_url, json=opp) if resp.status_code == 200: - logging.info("Successfully posted to beacon") + logging.info("Successfully broadcasted the opportunity") else: logging.error( - f"Failed to post to beacon, status code: {resp.status_code}, response: {resp.text}" + f"Failed to post to liquidation server, status code: {resp.status_code}, response: {resp.text}" ) else: diff --git a/per_sdk/searcher/simple_searcher.py b/per_sdk/searcher/simple_searcher.py index 7699c5d7..007d3448 100644 --- a/per_sdk/searcher/simple_searcher.py +++ b/per_sdk/searcher/simple_searcher.py @@ -4,17 +4,18 @@ from typing import TypedDict import httpx -from beacon.searcher.searcher_utils import ( +from eth_account import Account +from eth_account.signers.local import LocalAccount + +from per_sdk.searcher.searcher_utils import ( UserLiquidationParams, construct_signature_liquidator, ) -from beacon.utils.endpoints import ( - BEACON_SERVER_ENDPOINT_BID, - BEACON_SERVER_ENDPOINT_GETOPPS, +from per_sdk.utils.endpoints import ( + LIQUIDATION_SERVER_ENDPOINT_BID, + LIQUIDATION_SERVER_ENDPOINT_GETOPPS, ) -from beacon.utils.types_liquidation_adapter import LiquidationOpportunity -from eth_account import Account -from eth_account.signers.local import LocalAccount +from per_sdk.utils.types_liquidation_adapter import LiquidationOpportunity BID = 10 VALID_UNTIL = 1_000_000_000_000 @@ -101,7 +102,7 @@ async def main(): client = httpx.AsyncClient() while True: accounts_liquidatable = ( - await client.get(BEACON_SERVER_ENDPOINT_GETOPPS, params=params) + await client.get(LIQUIDATION_SERVER_ENDPOINT_GETOPPS, params=params) ).json() for liquidation_opp in accounts_liquidatable: @@ -117,7 +118,7 @@ async def main(): liquidation_opp, sk_liquidator, valid_until, bid ) - resp = await client.post(BEACON_SERVER_ENDPOINT_BID, json=tx) + resp = await client.post(LIQUIDATION_SERVER_ENDPOINT_BID, json=tx) print(resp.text) await asyncio.sleep(5) diff --git a/per_sdk/utils/endpoints.py b/per_sdk/utils/endpoints.py index 5c6aa67c..9b1fa2b3 100644 --- a/per_sdk/utils/endpoints.py +++ b/per_sdk/utils/endpoints.py @@ -1,10 +1,12 @@ -BEACON_SERVER_ENDPOINT = "http://localhost:9000" +LIQUIDATION_SERVER_ENDPOINT = "http://localhost:9000" AUCTION_SERVER_ENDPOINT = "http://localhost:9000/bid" -BEACON_SERVER_ENDPOINT_SURFACE = ( - f"{BEACON_SERVER_ENDPOINT}/liquidation/submit_opportunity" +LIQUIDATION_SERVER_ENDPOINT_SURFACE = ( + f"{LIQUIDATION_SERVER_ENDPOINT}/liquidation/submit_opportunity" ) -BEACON_SERVER_ENDPOINT_GETOPPS = ( - f"{BEACON_SERVER_ENDPOINT}/liquidation/fetch_opportunities" +LIQUIDATION_SERVER_ENDPOINT_GETOPPS = ( + f"{LIQUIDATION_SERVER_ENDPOINT}/liquidation/fetch_opportunities" +) +LIQUIDATION_SERVER_ENDPOINT_BID = ( + f"{LIQUIDATION_SERVER_ENDPOINT}/liquidation/bid_opportunity" ) -BEACON_SERVER_ENDPOINT_BID = f"{BEACON_SERVER_ENDPOINT}/liquidation/bid_opportunity" From 3bb95ddf4a1e1ce6f80cd071ee707be3fbf9e887 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 16:25:09 +0100 Subject: [PATCH 19/41] Fix ci for poetry --- .github/actions/python-poetry/action.yaml | 24 +++++++++++++++++++++++ .github/workflows/ci-pre-commit.yml | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 .github/actions/python-poetry/action.yaml diff --git a/.github/actions/python-poetry/action.yaml b/.github/actions/python-poetry/action.yaml new file mode 100644 index 00000000..96412db1 --- /dev/null +++ b/.github/actions/python-poetry/action.yaml @@ -0,0 +1,24 @@ +name: Python Poetry +description: Sets up a Python environment with Poetry + +inputs: + python-version: + required: false + description: Python version + default: "3.10" + poetry-version: + required: false + description: Poetry version + default: "1.2.2" + +runs: + using: composite + steps: + - uses: actions/setup-python@v2 + with: + python-version: ${{ inputs.python-version }} + - uses: abatilo/actions-poetry@v2.0.0 + with: + poetry-version: ${{ inputs.poetry-version }} + - run: poetry install + shell: sh diff --git a/.github/workflows/ci-pre-commit.yml b/.github/workflows/ci-pre-commit.yml index ad6c22bf..36dc3207 100644 --- a/.github/workflows/ci-pre-commit.yml +++ b/.github/workflows/ci-pre-commit.yml @@ -13,7 +13,7 @@ jobs: with: # Need to grab the history of the PR fetch-depth: 0 - - uses: actions/setup-python@v2 + - uses: ./.github/actions/python-poetry - uses: actions-rs/toolchain@v1 with: profile: minimal From 589402375e45811bea244a9460dd65d61b8a5c03 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 16:28:16 +0100 Subject: [PATCH 20/41] Fix CI part 2 --- .github/actions/python-poetry/action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/python-poetry/action.yaml b/.github/actions/python-poetry/action.yaml index 96412db1..7790866d 100644 --- a/.github/actions/python-poetry/action.yaml +++ b/.github/actions/python-poetry/action.yaml @@ -20,5 +20,5 @@ runs: - uses: abatilo/actions-poetry@v2.0.0 with: poetry-version: ${{ inputs.poetry-version }} - - run: poetry install + - run: poetry -C per_sdk install shell: sh From 139c010fe26d7c2c6ad53ed481c4e034109feca5 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 16:31:23 +0100 Subject: [PATCH 21/41] Update poetry version --- .github/actions/python-poetry/action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/python-poetry/action.yaml b/.github/actions/python-poetry/action.yaml index 7790866d..260ed3a6 100644 --- a/.github/actions/python-poetry/action.yaml +++ b/.github/actions/python-poetry/action.yaml @@ -9,7 +9,7 @@ inputs: poetry-version: required: false description: Poetry version - default: "1.2.2" + default: "1.6.1" runs: using: composite From 596054d3b4edf4d1708f7c6b1989f50f8c1b2fc9 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 16:32:49 +0100 Subject: [PATCH 22/41] Adjust requirements --- per_sdk/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/per_sdk/pyproject.toml b/per_sdk/pyproject.toml index 243596b4..5b628583 100644 --- a/per_sdk/pyproject.toml +++ b/per_sdk/pyproject.toml @@ -7,7 +7,7 @@ license = "Apache-2" readme = "README.md" [tool.poetry.dependencies] -python = "^3.11" +python = "^3.10" aiohttp = "3.9.1" aiosignal = "1.3.1" anyio = "4.2.0" From 326975e5ffda8c8d51a48c85f2428130ecab7e29 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 16:37:50 +0100 Subject: [PATCH 23/41] Adjust versioning again --- .github/actions/python-poetry/action.yaml | 2 +- per_sdk/pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/python-poetry/action.yaml b/.github/actions/python-poetry/action.yaml index 260ed3a6..07368c38 100644 --- a/.github/actions/python-poetry/action.yaml +++ b/.github/actions/python-poetry/action.yaml @@ -5,7 +5,7 @@ inputs: python-version: required: false description: Python version - default: "3.10" + default: "3.11" poetry-version: required: false description: Poetry version diff --git a/per_sdk/pyproject.toml b/per_sdk/pyproject.toml index 5b628583..243596b4 100644 --- a/per_sdk/pyproject.toml +++ b/per_sdk/pyproject.toml @@ -7,7 +7,7 @@ license = "Apache-2" readme = "README.md" [tool.poetry.dependencies] -python = "^3.10" +python = "^3.11" aiohttp = "3.9.1" aiosignal = "1.3.1" anyio = "4.2.0" From 2869b88e014db2fd9fedca81aeb2759f66ebc8d4 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 16:54:18 +0100 Subject: [PATCH 24/41] Final fix --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b3535ca8..88a64054 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,6 +40,7 @@ repos: - id: isort name: isort entry: poetry -C per_sdk run isort --profile=black per_sdk + pass_filenames: false language: system - id: black name: black From 5903debcd9ad50333dee8a1ab43f0a88aa621bbe Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 16:57:24 +0100 Subject: [PATCH 25/41] Get hermes endpoint as parameter in simulator --- vault-simulator/src/config.rs | 5 +++++ vault-simulator/src/simulator.rs | 16 ++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/vault-simulator/src/config.rs b/vault-simulator/src/config.rs index 3eaf98f8..5234157e 100644 --- a/vault-simulator/src/config.rs +++ b/vault-simulator/src/config.rs @@ -57,6 +57,11 @@ pub struct SimulatorOptions { /// The address of the token vault contract to interact with #[arg(long = "vault-contract")] pub vault_contract: Address, + + /// The endpoint to use for fetching pyth prices + #[arg(long = "price-endpoint")] + #[arg(default_value = "https://hermes.pyth.network")] + pub price_endpoint: Url, } #[derive(Args, Clone, Debug)] diff --git a/vault-simulator/src/simulator.rs b/vault-simulator/src/simulator.rs index fc71ad15..f5dbce13 100644 --- a/vault-simulator/src/simulator.rs +++ b/vault-simulator/src/simulator.rs @@ -6,7 +6,6 @@ use { }, anyhow::{ anyhow, - Context, Result, }, base64::prelude::*, @@ -126,9 +125,10 @@ async fn setup_client( Ok(client) } -async fn get_latest_updates(feed_ids: Vec) -> Result> { +async fn get_latest_updates(price_endpoint: Url, feed_ids: Vec) -> Result> { + let base_url = price_endpoint.join("/api/latest_price_feeds?verbose=true&binary=true")?; let url = Url::parse_with_params( - "https://hermes.pyth.network/api/latest_price_feeds?verbose=true&binary=true", + base_url.as_str(), feed_ids .iter() .map(|id| ("ids[]", id.to_string())) @@ -139,7 +139,7 @@ async fn get_latest_updates(feed_ids: Vec) -> Result> { let updates = response.json::().await?; (updates) .as_array() - .context(format!("Invalid response: {:?}", updates))? + .ok_or(anyhow!("Invalid response: {:?}", updates))? .into_iter() .map(|update| parse_update(update.clone())) .collect() @@ -175,10 +175,10 @@ pub async fn run_simulator(simulator_options: SimulatorOptions) -> Result<()> { ); // get the latest pyth updates - let updates = get_latest_updates(vec![ - collateral_info.price_id.clone(), - debt_info.price_id.clone(), - ]) + let updates = get_latest_updates( + simulator_options.price_endpoint, + vec![collateral_info.price_id.clone(), debt_info.price_id.clone()], + ) .await?; let collateral_update = updates[0].clone(); let debt_update = updates[1].clone(); From fb20273af0f3b27bd4f571064ebe9c99791917c0 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 17:15:13 +0100 Subject: [PATCH 26/41] Setup the new account from scratch --- vault-simulator/src/config.rs | 6 +++++- vault-simulator/src/simulator.rs | 10 +++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/vault-simulator/src/config.rs b/vault-simulator/src/config.rs index 5234157e..6f09ab9d 100644 --- a/vault-simulator/src/config.rs +++ b/vault-simulator/src/config.rs @@ -22,7 +22,7 @@ pub enum Options { /// Run the simulator. Run(SimulatorOptions), - /// Setup an already funded searcher account with ERC20 tokens and WETH. + /// Setup a new searcher account with ERC20 tokens and WETH using an existing account. CreateSearcher(SearcherOptions), /// Deploy the token vault contract. @@ -73,6 +73,10 @@ pub struct SearcherOptions { /// The address of the liquidation adapter contract to use for approvals #[arg(long = "adapter-contract")] pub adapter_contract: Address, + + /// Private key of the searcher, used for minting and approving tokens + #[arg(long = "searcher-private-key")] + pub searcher_private_key: String, } #[derive(Args, Clone, Debug)] diff --git a/vault-simulator/src/simulator.rs b/vault-simulator/src/simulator.rs index f5dbce13..5a4e1344 100644 --- a/vault-simulator/src/simulator.rs +++ b/vault-simulator/src/simulator.rs @@ -28,6 +28,7 @@ use { }, types::{ Bytes, + TransactionRequest, U256, }, }, @@ -260,8 +261,15 @@ pub async fn deploy_contract(options: DeployOptions) -> Result<()> { pub async fn create_searcher(searcher_options: SearcherOptions) -> Result<()> { let options = searcher_options.run_options; - let client = setup_client(options.private_key, options.rpc_addr).await?; + let funder_client = setup_client(options.private_key, options.rpc_addr.clone()).await?; + let client = setup_client(searcher_options.searcher_private_key, options.rpc_addr).await?; let wallet_address = client.signer().address(); + let tx = TransactionRequest::new() + .to(wallet_address) + .value(U256::exp10(19)) + .from(funder_client.signer().address()); + funder_client.send_transaction(tx, None).await?.await?; + tracing::info!("10 ETH sent to searcher wallet"); for token in options.tokens.iter() { let token_contract = ERC20::new(*token, client.clone()); token_contract From 0e4d3e0ad666011ed5f26c541a881a754df30965 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 19:32:56 +0100 Subject: [PATCH 27/41] Add interval option for simulator to create vaults periodically --- vault-simulator/src/config.rs | 5 +++++ vault-simulator/src/main.rs | 15 +++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/vault-simulator/src/config.rs b/vault-simulator/src/config.rs index 6f09ab9d..8d002a4d 100644 --- a/vault-simulator/src/config.rs +++ b/vault-simulator/src/config.rs @@ -62,6 +62,11 @@ pub struct SimulatorOptions { #[arg(long = "price-endpoint")] #[arg(default_value = "https://hermes.pyth.network")] pub price_endpoint: Url, + + // Interval in seconds to create a new vault + #[arg(long = "interval")] + #[arg(default_value = "5")] + pub interval: u64, } #[derive(Args, Clone, Debug)] diff --git a/vault-simulator/src/main.rs b/vault-simulator/src/main.rs index cfc3e13c..0ee8c962 100644 --- a/vault-simulator/src/main.rs +++ b/vault-simulator/src/main.rs @@ -1,7 +1,10 @@ use { anyhow::Result, clap::Parser, - std::io::IsTerminal, + std::{ + io::IsTerminal, + time::Duration, + }, tracing_subscriber::filter::LevelFilter, }; @@ -32,9 +35,13 @@ async fn main() -> Result<()> { // Parse the command line arguments with StructOpt, will exit automatically on `--help` or // with invalid arguments. match config::Options::parse() { - config::Options::Run(opts) => { - simulator::run_simulator(opts).await?; - } + config::Options::Run(opts) => loop { + let single_run = simulator::run_simulator(opts.clone()).await; + if let Err(err) = single_run { + tracing::error!("Error running simulator: {:?}", err); + } + tokio::time::sleep(Duration::from_secs(opts.interval)).await; + }, config::Options::CreateSearcher(opts) => { simulator::create_searcher(opts).await?; } From 8d13521910ee9f9bbf23b26584a55e532dc624ea Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Wed, 31 Jan 2024 19:34:04 +0100 Subject: [PATCH 28/41] Improve logging on per_sdk --- per_sdk/protocols/token_vault_monitor.py | 32 ++++++++++---- per_sdk/searcher/simple_searcher.py | 56 ++++++++++++++++++------ 2 files changed, 65 insertions(+), 23 deletions(-) diff --git a/per_sdk/protocols/token_vault_monitor.py b/per_sdk/protocols/token_vault_monitor.py index 30cc15aa..8d3af9ca 100644 --- a/per_sdk/protocols/token_vault_monitor.py +++ b/per_sdk/protocols/token_vault_monitor.py @@ -12,6 +12,8 @@ from per_sdk.utils.pyth_prices import PriceFeed, PriceFeedClient from per_sdk.utils.types_liquidation_adapter import LiquidationOpportunity +logger = logging.getLogger(__name__) + class ProtocolAccount(TypedDict): """ @@ -111,8 +113,7 @@ def create_liquidation_opp( """ price_updates = [base64.b64decode(update["vaa"]) for update in prices] - for update in prices: - print(update["feed_id"], update["price"]["publish_time"]) + calldata = self.token_vault.encodeABI( fn_name="liquidateWithPriceUpdate", args=[account["account_number"], price_updates], @@ -198,7 +199,8 @@ async def get_liquidation_opportunities(self) -> list[LiquidationOpportunity]: int(price_collateral["price"]["price"]) * account["amount_collateral"] ) value_debt = int(price_debt["price"]["price"]) * account["amount_debt"] - print(account["account_number"], value_collateral / value_debt) + health = value_collateral / value_debt + logger.debug(f"Account {account['account_number']} health: {health}") if ( value_debt * int(account["min_health_ratio"]) > value_collateral * 10**18 @@ -211,6 +213,7 @@ async def get_liquidation_opportunities(self) -> list[LiquidationOpportunity]: async def main(): parser = argparse.ArgumentParser() + parser.add_argument("-v", "--verbose", action="count", default=0) parser.add_argument( "--rpc-url", type=str, @@ -245,8 +248,14 @@ async def main(): ) args = parser.parse_args() - logging.basicConfig(level=logging.INFO) - logging.getLogger("httpx").propagate = False + logger.setLevel(logging.INFO if args.verbose == 0 else logging.DEBUG) + log_handler = logging.StreamHandler() + formatter = logging.Formatter( + "%(asctime)s %(levelname)s:%(name)s:%(module)s %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + log_handler.setFormatter(formatter) + logger.addHandler(log_handler) monitor = VaultMonitor(args.rpc_url, args.vault_contract, args.weth_contract) @@ -256,16 +265,21 @@ async def main(): if args.broadcast: client = httpx.AsyncClient() for opp in opportunities: - resp = await client.post(args.liquidation_server_url, json=opp) + try: + resp = await client.post(args.liquidation_server_url, json=opp) + except Exception as e: + logger.error(f"Failed to post to liquidation server: {e}") + await asyncio.sleep(1) + continue if resp.status_code == 200: - logging.info("Successfully broadcasted the opportunity") + logger.info("Successfully broadcasted the opportunity") else: - logging.error( + logger.error( f"Failed to post to liquidation server, status code: {resp.status_code}, response: {resp.text}" ) else: - logging.info( + logger.info( f"List of liquidatable accounts:\n{json.dumps(opportunities, indent=2)}" ) diff --git a/per_sdk/searcher/simple_searcher.py b/per_sdk/searcher/simple_searcher.py index 007d3448..ab25cccd 100644 --- a/per_sdk/searcher/simple_searcher.py +++ b/per_sdk/searcher/simple_searcher.py @@ -5,7 +5,6 @@ import httpx from eth_account import Account -from eth_account.signers.local import LocalAccount from per_sdk.searcher.searcher_utils import ( UserLiquidationParams, @@ -17,15 +16,17 @@ ) from per_sdk.utils.types_liquidation_adapter import LiquidationOpportunity -BID = 10 +logger = logging.getLogger(__name__) + VALID_UNTIL = 1_000_000_000_000 def assess_liquidation_opportunity( + default_bid: int, opp: LiquidationOpportunity, ) -> UserLiquidationParams | None: user_liquidation_params: UserLiquidationParams = { - "bid": BID, + "bid": default_bid, "valid_until": VALID_UNTIL, } return user_liquidation_params @@ -50,8 +51,7 @@ def create_liquidation_transaction( (opp["contract"], int(opp["amount"])) for opp in opp["receipt_tokens"] ] - account: LocalAccount = Account.from_key(sk_liquidator) - liquidator = account.address + liquidator = Account.from_key(sk_liquidator).address liq_calldata = bytes.fromhex(opp["calldata"].replace("0x", "")) signature_liquidator = construct_signature_liquidator( @@ -80,6 +80,7 @@ def create_liquidation_transaction( async def main(): parser = argparse.ArgumentParser() + parser.add_argument("-v", "--verbose", action="count", default=0) parser.add_argument( "--private-key", type=str, @@ -92,21 +93,43 @@ async def main(): required=True, help="Chain ID of the network to monitor for liquidation opportunities", ) + parser.add_argument( + "--bid", + type=int, + default=10, + help="Default amount of bid for liquidation opportunities", + ) args = parser.parse_args() - logging.basicConfig(level=logging.INFO) - logging.getLogger("httpx").propagate = False + logger.setLevel(logging.INFO if args.verbose == 0 else logging.DEBUG) + log_handler = logging.StreamHandler() + formatter = logging.Formatter( + "%(asctime)s %(levelname)s:%(name)s:%(module)s %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + log_handler.setFormatter(formatter) + logger.addHandler(log_handler) params = {"chain_id": args.chain_id} sk_liquidator = args.private_key + liquidator = Account.from_key(sk_liquidator).address + logger.info("Liquidator address: %s", liquidator) client = httpx.AsyncClient() while True: - accounts_liquidatable = ( - await client.get(LIQUIDATION_SERVER_ENDPOINT_GETOPPS, params=params) - ).json() - + try: + accounts_liquidatable = ( + await client.get(LIQUIDATION_SERVER_ENDPOINT_GETOPPS, params=params) + ).json() + except Exception as e: + logger.error(e) + await asyncio.sleep(5) + continue + + logger.debug("Found %d liquidation opportunities", len(accounts_liquidatable)) for liquidation_opp in accounts_liquidatable: - user_liquidation_params = assess_liquidation_opportunity(liquidation_opp) + user_liquidation_params = assess_liquidation_opportunity( + args.bid, liquidation_opp + ) if user_liquidation_params is not None: bid, valid_until = ( @@ -119,9 +142,14 @@ async def main(): ) resp = await client.post(LIQUIDATION_SERVER_ENDPOINT_BID, json=tx) + logger.info( + "Submitted bid amount %s for opportunity %s, server response: %s", + bid, + liquidation_opp["opportunity_id"], + resp.text, + ) - print(resp.text) - await asyncio.sleep(5) + await asyncio.sleep(1) if __name__ == "__main__": From 6a80dac844061eee2696b24c1a48cdabb9faf530 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Thu, 1 Feb 2024 15:49:58 +0100 Subject: [PATCH 29/41] Reduce ETH amounts to be more reasonable in actual testnets --- vault-simulator/src/simulator.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vault-simulator/src/simulator.rs b/vault-simulator/src/simulator.rs index 5a4e1344..0e0b61a2 100644 --- a/vault-simulator/src/simulator.rs +++ b/vault-simulator/src/simulator.rs @@ -266,10 +266,10 @@ pub async fn create_searcher(searcher_options: SearcherOptions) -> Result<()> { let wallet_address = client.signer().address(); let tx = TransactionRequest::new() .to(wallet_address) - .value(U256::exp10(19)) + .value(U256::exp10(16)) .from(funder_client.signer().address()); funder_client.send_transaction(tx, None).await?.await?; - tracing::info!("10 ETH sent to searcher wallet"); + tracing::info!("0.01 ETH sent to searcher wallet"); for token in options.tokens.iter() { let token_contract = ERC20::new(*token, client.clone()); token_contract @@ -291,7 +291,7 @@ pub async fn create_searcher(searcher_options: SearcherOptions) -> Result<()> { let weth_contract = WETH9::new(options.weth, client.clone()); weth_contract .deposit() - .value(U256::exp10(18)) + .value(U256::exp10(14)) .send() .await? .await?; @@ -302,7 +302,7 @@ pub async fn create_searcher(searcher_options: SearcherOptions) -> Result<()> { .await?; let balance = weth_contract.balance_of(wallet_address).await?; tracing::info!( - "1 ETH deposited into WETH and approved to use by liquidation adapter, current balance: {}", + ".0001 ETH deposited into WETH and approved to use by liquidation adapter, current balance: {} wei", balance ); Ok(()) From 84407e972159175a0e4f63e1b67c78274cd3c27c Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Thu, 1 Feb 2024 15:57:53 +0100 Subject: [PATCH 30/41] Correct usage of chain_id in scripts --- per_sdk/protocols/token_vault_monitor.py | 17 ++++++++++++++--- per_sdk/searcher/simple_searcher.py | 1 - 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/per_sdk/protocols/token_vault_monitor.py b/per_sdk/protocols/token_vault_monitor.py index 8d3af9ca..813ca7cf 100644 --- a/per_sdk/protocols/token_vault_monitor.py +++ b/per_sdk/protocols/token_vault_monitor.py @@ -42,10 +42,13 @@ def get_vault_abi(): class VaultMonitor: - def __init__(self, rpc_url: str, contract_address: str, weth_address: str): + def __init__( + self, rpc_url: str, contract_address: str, weth_address: str, chain_id: str + ): self.rpc_url = rpc_url self.contract_address = contract_address self.weth_address = weth_address + self.chain_id = chain_id self.w3 = web3.AsyncWeb3(web3.AsyncHTTPProvider(rpc_url)) self.token_vault = self.w3.eth.contract( @@ -141,7 +144,7 @@ def create_liquidation_opp( ] opp: LiquidationOpportunity = { - "chain_id": "development", + "chain_id": self.chain_id, "contract": self.contract_address, "calldata": calldata, "permission_key": permission, @@ -214,6 +217,12 @@ async def get_liquidation_opportunities(self) -> list[LiquidationOpportunity]: async def main(): parser = argparse.ArgumentParser() parser.add_argument("-v", "--verbose", action="count", default=0) + parser.add_argument( + "--chain-id", + type=str, + required=True, + help="Chain ID of the network to monitor for liquidation opportunities", + ) parser.add_argument( "--rpc-url", type=str, @@ -257,7 +266,9 @@ async def main(): log_handler.setFormatter(formatter) logger.addHandler(log_handler) - monitor = VaultMonitor(args.rpc_url, args.vault_contract, args.weth_contract) + monitor = VaultMonitor( + args.rpc_url, args.vault_contract, args.weth_contract, args.chain_id + ) while True: opportunities = await monitor.get_liquidation_opportunities() diff --git a/per_sdk/searcher/simple_searcher.py b/per_sdk/searcher/simple_searcher.py index ab25cccd..4629421c 100644 --- a/per_sdk/searcher/simple_searcher.py +++ b/per_sdk/searcher/simple_searcher.py @@ -66,7 +66,6 @@ def create_liquidation_transaction( ) json_body = { - "chain_id": opp["chain_id"], "opportunity_id": opp["opportunity_id"], "permission_key": opp["permission_key"], "bid_amount": str(bid), From d3c0d078a60c5b4d74f2bc8693beabcea1b2c5f4 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Thu, 1 Feb 2024 17:09:11 +0100 Subject: [PATCH 31/41] Minor refactor --- per_multicall/script/Vault.s.sol | 35 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/per_multicall/script/Vault.s.sol b/per_multicall/script/Vault.s.sol index 0eea6a52..d9a598c9 100644 --- a/per_multicall/script/Vault.s.sol +++ b/per_multicall/script/Vault.s.sol @@ -27,7 +27,7 @@ import "../src/Errors.sol"; contract VaultScript is Script { string public latestEnvironmentPath = "latestEnvironment.json"; - function getAnvil() public view returns (address, uint256) { + function getDeployer() public view returns (address, uint256) { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); address deployerAddress = vm.addr(deployerPrivateKey); return (deployerAddress, deployerPrivateKey); @@ -45,7 +45,7 @@ contract VaultScript is Script { ); console.log("pk per operator", perOperatorAddress); console.log("sk per operator", perOperatorSk); - payable(perOperatorAddress).transfer(10 ether); + payable(perOperatorAddress).transfer(0.01 ether); PERMulticall multicall = new PERMulticall(perOperatorAddress, 0); console.log("deployed PER contract at", address(multicall)); LiquidationAdapter liquidationAdapter = new LiquidationAdapter( @@ -77,8 +77,8 @@ contract VaultScript is Script { public returns (address, address, address, address, address) { - (, uint256 skanvil) = getAnvil(); - vm.startBroadcast(skanvil); + (, uint256 skDeployer) = getDeployer(); + vm.startBroadcast(skDeployer); address weth = deployWeth(); (address per, address liquidationAdapter) = deployPER(weth); address mockPyth = deployMockPyth(); @@ -93,10 +93,11 @@ contract VaultScript is Script { The erc-20 tokens have their actual name as symbol and pyth price feed id as their name. A huge amount of these tokens are minted to the token vault @param pyth The address of the already deployed pyth contract to use */ - function setupTestnet(address pyth) public { - (, uint256 skanvil) = getAnvil(); - vm.startBroadcast(skanvil); - address weth = deployWeth(); + function setupTestnet(address pyth, address weth) public { + (, uint256 skDeployer) = getDeployer(); + vm.startBroadcast(skDeployer); + if (pyth == address(0)) pyth = deployMockPyth(); + if (weth == address(0)) weth = deployWeth(); (address per, address liquidationAdapter) = deployPER(weth); address vault = deployVault(per, pyth); address[] memory tokens = new address[](5); @@ -179,19 +180,19 @@ contract VaultScript is Script { ); // TODO: these are mnemonic wallets. figure out how to transfer ETH from them outside of explicitly hardcoding them here. - (address pkanvil, uint256 skanvil) = getAnvil(); + (address pkDeployer, uint256 skDeployer) = getDeployer(); // transfer ETH to relevant wallets - vm.startBroadcast(skanvil); - console.log("balance of pk anvil", pkanvil.balance); + vm.startBroadcast(skDeployer); + console.log("balance of deployer", pkDeployer.balance); payable(addressesScript[3]).transfer(10 ether); - console.log("balance of pk anvil", pkanvil.balance); + console.log("balance of deployer", pkDeployer.balance); payable(addressesScript[0]).transfer(10 ether); - console.log("balance of pk anvil", pkanvil.balance); + console.log("balance of deployer", pkDeployer.balance); payable(addressesScript[1]).transfer(10 ether); - console.log("balance of pk anvil", pkanvil.balance); + console.log("balance of deployer", pkDeployer.balance); payable(addressesScript[2]).transfer(10 ether); - console.log("balance of pk anvil", pkanvil.balance); + console.log("balance of deployer", pkDeployer.balance); payable(addressesScript[4]).transfer(10 ether); vm.stopBroadcast(); @@ -224,8 +225,8 @@ contract VaultScript is Script { console.log("contract of searcher B is", address(searcherB)); // fund the searcher contracts - vm.startBroadcast(skanvil); - console.log("balance of pkanvil", pkanvil.balance); + vm.startBroadcast(skDeployer); + console.log("balance of deployer", pkDeployer.balance); payable(address(searcherA)).transfer(1 ether); payable(address(searcherB)).transfer(1 ether); vm.stopBroadcast(); From f407a485826bc75c50f9de88dcbcc547a36c7fc2 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Thu, 1 Feb 2024 17:11:31 +0100 Subject: [PATCH 32/41] Fix api docs --- auction-server/src/api.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/auction-server/src/api.rs b/auction-server/src/api.rs index f7a0f36b..e3be2a8b 100644 --- a/auction-server/src/api.rs +++ b/auction-server/src/api.rs @@ -93,7 +93,11 @@ pub enum RestError { /// The chain id is not supported InvalidChainId, /// The simulation failed - SimulationError { result: Bytes, reason: String }, + SimulationError { + #[schema(value_type=String)] + result: Bytes, + reason: String, + }, /// The order was not found OpportunityNotFound, /// The server cannot currently communicate with the blockchain, so is not able to verify From dc174450c0f5031046ae318436fbc1652df41989 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Thu, 1 Feb 2024 17:11:56 +0100 Subject: [PATCH 33/41] Remove the opportunity upon sucessfull submission --- auction-server/src/auction.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/auction-server/src/auction.rs b/auction-server/src/auction.rs index ab7f44de..30f288f9 100644 --- a/auction-server/src/auction.rs +++ b/auction-server/src/auction.rs @@ -191,8 +191,14 @@ pub async fn run_submission_loop(store: Arc) { match submission { Ok(receipt) => match receipt { Some(receipt) => { - tracing::info!("Submitted transaction: {:?}", receipt); + tracing::debug!("Submitted transaction: {:?}", receipt); chain_store.bids.write().await.remove(&permission_key); + store + .liquidation_store + .opportunities + .write() + .await + .remove(&permission_key); //TODO: this should be done via opportunity verifier and only when the opportunity is not valid anymore } None => { tracing::error!("Failed to receive transaction receipt"); @@ -210,7 +216,7 @@ pub async fn run_submission_loop(store: Arc) { } } } - tokio::time::sleep(Duration::from_secs(10)).await; // this should be replaced by a subscription to the chain and trigger on new blocks + tokio::time::sleep(Duration::from_secs(5)).await; // this should be replaced by a subscription to the chain and trigger on new blocks } tracing::info!("Shutting down transaction submitter..."); } From 28d0a8851046dfc2adb4e6caac5852cc645dbf9b Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Thu, 1 Feb 2024 17:44:31 +0100 Subject: [PATCH 34/41] Move over documentations from the other PR --- per_sdk/protocols/README.md | 9 ++++ per_sdk/searcher/README.md | 10 +++++ per_sdk/searcher/searcher_utils.py | 20 +++++---- per_sdk/searcher/simple_searcher.py | 66 +++++++++++++++++------------ 4 files changed, 70 insertions(+), 35 deletions(-) create mode 100644 per_sdk/protocols/README.md create mode 100644 per_sdk/searcher/README.md diff --git a/per_sdk/protocols/README.md b/per_sdk/protocols/README.md new file mode 100644 index 00000000..ced3b8e0 --- /dev/null +++ b/per_sdk/protocols/README.md @@ -0,0 +1,9 @@ +# Opportunity Monitor + +The monitor is the off-chain service that exposes liquidation opportunities on integrated protocols to searchers. Protocols surface their liquidatable vaults/accounts along with the calldata and the token denominations and amounts involved in the transaction. Searchers can query these opportunities from the liquidation server. If they wish to act on an opportunity, they can simply construct a signature based off the information in the opportunity. + +The LiquidationAdapter contract that is part of the Express Relay on-chain stack allows searchers to perform liquidations across different protocols without needing to deploy their own contracts or perform bespoke integration work. The monitor service is important in enabling this, as it publishes the all the necessary information that searchers need for signing their intent on executing the liquidations. + +Each protocol that integrates with Express Relay and the LiquidationAdapter workflow must provide code that publishes liquidation opportunities; the example file for the TokenVault dummy contract is found in `/protocols`. Some common types are defined in `utils/types_liquidation_adapter.py`, and standard functions for accessing Pyth prices can be found in `utils/pyth_prices.py`. The exact interface of the methods in the protocol's file is not important, but it should have a similar entrypoint with the same command line arguments and general behavior of sending liquidation opportunities to the liquidation server when specified. + +The party that runs the monitor can run the protocol-provided file to surface liquidation opportunities to the liquidation server. diff --git a/per_sdk/searcher/README.md b/per_sdk/searcher/README.md new file mode 100644 index 00000000..822e9317 --- /dev/null +++ b/per_sdk/searcher/README.md @@ -0,0 +1,10 @@ +# Searcher Integration + +Searchers can integrate with Express Relay by one of two means: + +1. Simple integration with LiquidationAdapter via an Externally Owned Account (EOA) +2. Advanced integration with PER using a customized searcher contract + +Option 2 requires searchers to handle individual protocol interfaces and smart contract risk, and it is similar in nature to how many searchers currently do liquidations via their own deployed contracts--searchers can now call into their smart contracts via the Express Relay workflow. This option allows for greater customization by the searcher, but requires additional work per each protocol that the searcher wants to integrate with. + +Meanwhile, option 1 requires much less work and does not require contract deployment by the searcher. For option 1, the searcher submits their bid on the liquidation opportunity to the liquidation server, which handles transaction submission, routing the liquidation logic to the protocol and also performs safety checks to ensure that the searcher is paying and receiving the appropriate amounts, as specified in the liquidation opportunity structure. The searcher can submit transactions signed by their EOA that has custody of the tokens they wish to repay with. Searchers can listen to liquidation opportunities using the liquidation server, and if they wish to bid on a liquidation opportunity, they can submit it via the same server. `searcher_template.py` contains a template for the actions that a searcher may wish to perform, namely getting and assessing opportunities at the Beacon server and constructing and sending a liquidation. Helper functions related to constructing the signature for the LiquidationAdapter contract are in `searcher_utils.py`. A sample workflow is in `searcherA.py` (note: this example lacks any serious evaluation of opportunities, and it simply carries out a liquidation if the opportunity is available). diff --git a/per_sdk/searcher/searcher_utils.py b/per_sdk/searcher/searcher_utils.py index 109f5b32..9bd5f752 100644 --- a/per_sdk/searcher/searcher_utils.py +++ b/per_sdk/searcher/searcher_utils.py @@ -2,10 +2,11 @@ import web3 from eth_abi import encode +from eth_account.datastructures import SignedMessage from web3.auto import w3 -class UserLiquidationParams(TypedDict): +class BidInfo(TypedDict): bid: int valid_until: int @@ -16,24 +17,23 @@ def construct_signature_liquidator( address: str, liq_calldata: bytes, value: int, - bid: int, - valid_until: int, + bid_info: BidInfo, secret_key: str, -): +) -> SignedMessage: """ - Constructs a signature for a liquidator's transaction to submit to the LiquidationAdapter contract. + Constructs a signature for a liquidator's bid to submit to the liquidation server. Args: repay_tokens: A list of tuples (token address, amount) representing the tokens to repay. receipt_tokens: A list of tuples (token address, amount) representing the tokens to receive. - address: The address of the LiquidationAdapter contract. + address: The address of the protocol contract for the liquidation. liq_calldata: The calldata for the liquidation method call. value: The value for the liquidation method call. bid: The amount of native token to bid on this opportunity. valid_until: The timestamp at which the transaction will expire. secret_key: A 0x-prefixed hex string representing the liquidator's private key. Returns: - An web3 ECDSASignature object, representing the liquidator's signature. + A SignedMessage object, representing the liquidator's signature. """ digest = encode( @@ -45,9 +45,11 @@ def construct_signature_liquidator( "uint256", "uint256", ], - [repay_tokens, receipt_tokens, address, liq_calldata, value, bid], + [repay_tokens, receipt_tokens, address, liq_calldata, value, bid_info["bid"]], + ) + msg_data = web3.Web3.solidity_keccak( + ["bytes", "uint256"], [digest, bid_info["valid_until"]] ) - msg_data = web3.Web3.solidity_keccak(["bytes", "uint256"], [digest, valid_until]) signature = w3.eth.account.signHash(msg_data, private_key=secret_key) return signature diff --git a/per_sdk/searcher/simple_searcher.py b/per_sdk/searcher/simple_searcher.py index 4629421c..7196d6c4 100644 --- a/per_sdk/searcher/simple_searcher.py +++ b/per_sdk/searcher/simple_searcher.py @@ -6,10 +6,7 @@ import httpx from eth_account import Account -from per_sdk.searcher.searcher_utils import ( - UserLiquidationParams, - construct_signature_liquidator, -) +from per_sdk.searcher.searcher_utils import BidInfo, construct_signature_liquidator from per_sdk.utils.endpoints import ( LIQUIDATION_SERVER_ENDPOINT_BID, LIQUIDATION_SERVER_ENDPOINT_GETOPPS, @@ -24,8 +21,21 @@ def assess_liquidation_opportunity( default_bid: int, opp: LiquidationOpportunity, -) -> UserLiquidationParams | None: - user_liquidation_params: UserLiquidationParams = { +) -> BidInfo | None: + """ + Assesses whether a liquidation opportunity is worth liquidating; if so, returns the bid and valid_until timestamp. Otherwise returns None. + This function determines whether the given opportunity deals with the specified repay and receipt tokens that the searcher wishes to transact in and whether it is profitable to execute the liquidation. + There are many ways to evaluate this, but the most common way is to check that the value of the amount the searcher will receive from the liquidation exceeds the value of the amount repaid. + Individual searchers will have their own methods to determine market impact and the profitability of conducting a liquidation. This function can be expanded to include external prices to perform this evaluation. + If the opporutnity is deemed worthwhile, this function can return a bid amount representing the amount of native token to bid on this opportunity, and a timestamp representing the time at which the transaction will expire. + Otherwise, this function can return None. + Args: + default_bid: The default amount of bid for liquidation opportunities. + opp: A LiquidationOpportunity object, representing a single liquidation opportunity. + Returns: + If the opportunity is deemed worthwhile, this function can return a BidInfo object, representing the user's bid and the timestamp at which the user's bid should expire. If the LiquidationOpportunity is not deemed worthwhile, this function can return None. + """ + user_liquidation_params = { "bid": default_bid, "valid_until": VALID_UNTIL, } @@ -42,8 +52,17 @@ class OpportunityBid(TypedDict): def create_liquidation_transaction( - opp: LiquidationOpportunity, sk_liquidator: str, valid_until: int, bid: int + opp: LiquidationOpportunity, sk_liquidator: str, bid_info: BidInfo ) -> OpportunityBid: + """ + Creates a bid for a liquidation opportunity. + Args: + opp: A LiquidationOpportunity object, representing a single liquidation opportunity. + sk_liquidator: A 0x-prefixed hex string representing the liquidator's private key. + bid_info: necessary information for the liquidation bid + Returns: + An OpportunityBid object which can be sent to the liquidation server + """ repay_tokens = [ (opp["contract"], int(opp["amount"])) for opp in opp["repay_tokens"] ] @@ -60,21 +79,20 @@ def create_liquidation_transaction( opp["contract"], liq_calldata, int(opp["value"]), - bid, - valid_until, + bid_info, sk_liquidator, ) - json_body = { + opportunity_bid = { "opportunity_id": opp["opportunity_id"], "permission_key": opp["permission_key"], - "bid_amount": str(bid), - "valid_until": str(valid_until), + "bid_amount": str(bid_info["bid"]), + "valid_until": str(bid_info["valid_until"]), "liquidator": liquidator, "signature": bytes(signature_liquidator.signature).hex(), } - return json_body + return opportunity_bid async def main(): @@ -109,7 +127,6 @@ async def main(): log_handler.setFormatter(formatter) logger.addHandler(log_handler) - params = {"chain_id": args.chain_id} sk_liquidator = args.private_key liquidator = Account.from_key(sk_liquidator).address logger.info("Liquidator address: %s", liquidator) @@ -117,7 +134,10 @@ async def main(): while True: try: accounts_liquidatable = ( - await client.get(LIQUIDATION_SERVER_ENDPOINT_GETOPPS, params=params) + await client.get( + LIQUIDATION_SERVER_ENDPOINT_GETOPPS, + params={"chain_id": args.chain_id}, + ) ).json() except Exception as e: logger.error(e) @@ -126,24 +146,18 @@ async def main(): logger.debug("Found %d liquidation opportunities", len(accounts_liquidatable)) for liquidation_opp in accounts_liquidatable: - user_liquidation_params = assess_liquidation_opportunity( - args.bid, liquidation_opp - ) - - if user_liquidation_params is not None: - bid, valid_until = ( - user_liquidation_params["bid"], - user_liquidation_params["valid_until"], - ) + bid_info = assess_liquidation_opportunity(args.bid, liquidation_opp) + + if bid_info is not None: tx = create_liquidation_transaction( - liquidation_opp, sk_liquidator, valid_until, bid + liquidation_opp, sk_liquidator, bid_info ) resp = await client.post(LIQUIDATION_SERVER_ENDPOINT_BID, json=tx) logger.info( "Submitted bid amount %s for opportunity %s, server response: %s", - bid, + bid_info["bid"], liquidation_opp["opportunity_id"], resp.text, ) From 394d8a9f8ff9d7bc2956efaae1f1fb35bdc020d5 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sat, 3 Feb 2024 11:47:45 +0100 Subject: [PATCH 35/41] Address comments --- auction-server/src/api/marketplace.rs | 12 +++++----- auction-server/src/api/rest.rs | 27 +++++++++-------------- auction-server/src/liquidation_adapter.rs | 18 +++++++++------ 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/auction-server/src/api/marketplace.rs b/auction-server/src/api/marketplace.rs index d4075961..c8066805 100644 --- a/auction-server/src/api/marketplace.rs +++ b/auction-server/src/api/marketplace.rs @@ -45,7 +45,9 @@ pub struct TokenQty { } /// A liquidation opportunity ready to be executed. -/// If a searcher signs the opportunity and have approved enough tokens to liquidation adapter, by calling this contract with the given calldata and structures, they will receive the tokens specified in the receipt_tokens field, and will send the tokens specified in the repay_tokens field. +/// If a searcher signs the opportunity and have approved enough tokens to liquidation adapter, +/// by calling this contract with the given calldata and structures, they will receive the tokens specified +/// in the receipt_tokens field, and will send the tokens specified in the repay_tokens field. #[derive(Serialize, Deserialize, ToSchema, Clone)] pub struct LiquidationOpportunity { /// The permission key required for succesful execution of the liquidation. @@ -68,8 +70,7 @@ pub struct LiquidationOpportunity { receipt_tokens: Vec, } -/// A submitted liquidation opportunity ready to be executed. -/// If a searcher signs the opportunity and have approved enough tokens to liquidation adapter, by calling this contract with the given calldata and structures, they will receive the tokens specified in the receipt_tokens field, and will send the tokens specified in the repay_tokens field. +/// Similar to LiquidationOpportunity, but with the opportunity id included. #[derive(Serialize, Deserialize, ToSchema, Clone)] pub struct LiquidationOpportunityWithId { /// The opportunity unique id @@ -104,7 +105,8 @@ fn parse_tokens(tokens: Vec) -> Result, RestError /// Submit a liquidation opportunity ready to be executed. /// -/// The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database and will be available for bidding. +/// The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database +/// and will be available for bidding. #[utoipa::path(post, path = "/liquidation/submit_opportunity", request_body = LiquidationOpportunity, responses( (status = 200, description = "Opportunity was stored succesfuly with the returned uuid", body = String), (status = 400, response=RestError) @@ -277,7 +279,7 @@ pub async fn bid_opportunity( Ok(_) => Ok("OK".to_string()), Err(e) => match e { RestError::SimulationError { result, reason } => { - let parsed = parse_revert_error(result.clone()); + let parsed = parse_revert_error(&result); match parsed { Some(decoded) => Err(RestError::BadParameters(decoded)), None => { diff --git a/auction-server/src/api/rest.rs b/auction-server/src/api/rest.rs index f093418e..d288c82d 100644 --- a/auction-server/src/api/rest.rs +++ b/auction-server/src/api/rest.rs @@ -1,10 +1,7 @@ use { crate::{ api::RestError, - auction::{ - per::MulticallStatus, - simulate_bids, - }, + auction::simulate_bids, state::{ SimulatedBid, Store, @@ -75,20 +72,16 @@ pub async fn handle_bid(store: Arc, bid: ParsedBid) -> Result { - let multicall_results: Vec = result; - if !multicall_results.iter().all(|x| x.external_success) { - let first_reason = multicall_results - .first() - .cloned() - .unwrap() - .multicall_revert_reason; - let first_result = multicall_results.first().cloned().unwrap().external_result; - return Err(RestError::SimulationError { - result: first_result, - reason: first_reason, + Ok(results) => { + results + .iter() + .find(|x| !x.external_success) + .map(|call_status| { + return Err(RestError::SimulationError { + result: call_status.external_result, + reason: call_status.multicall_revert_reason.clone(), + }); }); - } } Err(e) => { return match e { diff --git a/auction-server/src/liquidation_adapter.rs b/auction-server/src/liquidation_adapter.rs index b142ee3a..aae0bce1 100644 --- a/auction-server/src/liquidation_adapter.rs +++ b/auction-server/src/liquidation_adapter.rs @@ -79,14 +79,18 @@ pub fn verify_signature(params: liquidation_adapter::LiquidationCallParams) -> R }) } -pub fn parse_revert_error(revert: Bytes) -> Option { - let apdapter_decoded = - liquidation_adapter::LiquidationAdapterErrors::decode_with_selector(&revert) - .map(|err| format!("Liquidation Adapter Contract Revert Error: {:#?}", err)); - let erc20_decoded = erc20::ERC20Errors::decode_with_selector(&revert).map(|err| { - tracing::info!("ERC20 Contract Revert Error: {:#?}", err); - format!("ERC20 Contract Revert Error: {:#?}", err) +pub fn parse_revert_error(revert: &Bytes) -> Option { + let apdapter_decoded = liquidation_adapter::LiquidationAdapterErrors::decode_with_selector( + revert, + ) + .map(|decoded_error| { + format!( + "Liquidation Adapter Contract Revert Error: {:#?}", + decoded_error + ) }); + let erc20_decoded = erc20::ERC20Errors::decode_with_selector(revert) + .map(|decoded_error| format!("ERC20 Contract Revert Error: {:#?}", decoded_error)); apdapter_decoded.or(erc20_decoded) } From 31deb9b4942fa1739518619c1beabaa987083421 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 4 Feb 2024 12:16:42 +0100 Subject: [PATCH 36/41] Move error handling logic partly into auction Converting ContractError to RestErrors remain in api but logical error handling moved inside the auction module --- auction-server/src/api/rest.rs | 29 ++++++++++++----------------- auction-server/src/auction.rs | 25 ++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/auction-server/src/api/rest.rs b/auction-server/src/api/rest.rs index d288c82d..9c0999b9 100644 --- a/auction-server/src/api/rest.rs +++ b/auction-server/src/api/rest.rs @@ -1,7 +1,10 @@ use { crate::{ api::RestError, - auction::simulate_bids, + auction::{ + simulate_bids, + SimulationError, + }, state::{ SimulatedBid, Store, @@ -71,20 +74,12 @@ pub async fn handle_bid(store: Arc, bid: ParsedBid) -> Result { - results - .iter() - .find(|x| !x.external_success) - .map(|call_status| { - return Err(RestError::SimulationError { - result: call_status.external_result, - reason: call_status.multicall_revert_reason.clone(), - }); - }); - } - Err(e) => { - return match e { + if let Err(e) = call.await { + return match e { + SimulationError::LogicalError { result, reason } => { + Err(RestError::SimulationError { result, reason }) + } + SimulationError::ContractError(e) => match e { ContractError::Revert(reason) => Err(RestError::BadParameters(format!( "Contract Revert Error: {}", String::decode_with_selector(&reason) @@ -93,8 +88,8 @@ pub async fn handle_bid(store: Arc, bid: ParsedBid) -> Result Err(RestError::TemporarilyUnavailable), ContractError::ProviderError { e: _ } => Err(RestError::TemporarilyUnavailable), _ => Err(RestError::BadParameters(format!("Error: {}", e))), - } - } + }, + }; }; chain_store diff --git a/auction-server/src/auction.rs b/auction-server/src/auction.rs index 30f288f9..812c2dd9 100644 --- a/auction-server/src/auction.rs +++ b/auction-server/src/auction.rs @@ -55,6 +55,7 @@ pub type SignableProvider = pub type SignablePERContract = PER; impl TryFrom for Provider { + type Error = anyhow::Error; fn try_from(config: EthereumConfig) -> Result { Provider::::try_from(config.geth_rpc_addr.clone()).map_err(|err| { anyhow!( @@ -64,9 +65,13 @@ impl TryFrom for Provider { ) }) } - type Error = anyhow::Error; } + +pub enum SimulationError { + LogicalError { result: Bytes, reason: String }, + ContractError(ContractError>), +} pub async fn simulate_bids( per_operator: Address, provider: Provider, @@ -75,13 +80,27 @@ pub async fn simulate_bids( contracts: Vec
, calldata: Vec, bids: Vec, -) -> Result, ContractError>> { +) -> Result<(), SimulationError> { let client = Arc::new(provider); let per_contract = PERContract::new(chain_config.per_contract, client); let call = per_contract .multicall(permission, contracts, calldata, bids) .from(per_operator); - call.call().await + match call.await { + Ok(results) => { + let failed_result = results.iter().find(|x| !x.external_success); + if let Some(call_status) = failed_result { + return Err(SimulationError::LogicalError { + result: call_status.external_result.clone(), + reason: call_status.multicall_revert_reason.clone(), + }); + } + } + Err(e) => { + return Err(SimulationError::ContractError(e)); + } + }; + Ok(()) } #[derive(Debug)] From 1c06ebd20418cfe89b83ce9eb481520c4b4d951e Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 4 Feb 2024 13:40:51 +0100 Subject: [PATCH 37/41] Add build scripts --- auction-server/build.rs | 26 ++++++++++++++++++++++++++ auction-server/rust-toolchain.toml | 2 ++ vault-simulator/build.rs | 26 ++++++++++++++++++++++++++ vault-simulator/rust-toolchain.toml | 2 ++ 4 files changed, 56 insertions(+) create mode 100644 auction-server/build.rs create mode 100644 auction-server/rust-toolchain.toml create mode 100644 vault-simulator/build.rs create mode 100644 vault-simulator/rust-toolchain.toml diff --git a/auction-server/build.rs b/auction-server/build.rs new file mode 100644 index 00000000..6dd43c92 --- /dev/null +++ b/auction-server/build.rs @@ -0,0 +1,26 @@ +use std::process::Command; + +fn main() { + let contract_setup = r#" + cd ../per_multicall + forge build --via-ir + "#; + println!("cargo:rerun-if-changed=../per_multicall"); + + // Build the contracts and generate the ABIs. This is required for abigen! macro expansions to work. + let output = Command::new("sh") + .args(["-c", contract_setup]) + .output() + .expect("Failed to run build contracts command"); + if !output.status.success() { + panic!( + "Failed to build contracts: {}", + String::from_utf8_lossy(&output.stderr) + ); + } else { + println!( + "Built all solidity contracts {}", + String::from_utf8_lossy(&output.stdout) + ); + } +} diff --git a/auction-server/rust-toolchain.toml b/auction-server/rust-toolchain.toml new file mode 100644 index 00000000..292fe499 --- /dev/null +++ b/auction-server/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" diff --git a/vault-simulator/build.rs b/vault-simulator/build.rs new file mode 100644 index 00000000..6dd43c92 --- /dev/null +++ b/vault-simulator/build.rs @@ -0,0 +1,26 @@ +use std::process::Command; + +fn main() { + let contract_setup = r#" + cd ../per_multicall + forge build --via-ir + "#; + println!("cargo:rerun-if-changed=../per_multicall"); + + // Build the contracts and generate the ABIs. This is required for abigen! macro expansions to work. + let output = Command::new("sh") + .args(["-c", contract_setup]) + .output() + .expect("Failed to run build contracts command"); + if !output.status.success() { + panic!( + "Failed to build contracts: {}", + String::from_utf8_lossy(&output.stderr) + ); + } else { + println!( + "Built all solidity contracts {}", + String::from_utf8_lossy(&output.stdout) + ); + } +} diff --git a/vault-simulator/rust-toolchain.toml b/vault-simulator/rust-toolchain.toml new file mode 100644 index 00000000..292fe499 --- /dev/null +++ b/vault-simulator/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" From b82e4d0b2b19e1a8e2c156fd774e1041ed439701 Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 4 Feb 2024 13:48:08 +0100 Subject: [PATCH 38/41] Use config for poll interval --- auction-server/config.sample.yaml | 1 + auction-server/src/api.rs | 2 +- auction-server/src/config.rs | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/auction-server/config.sample.yaml b/auction-server/config.sample.yaml index a065f683..5738d869 100644 --- a/auction-server/config.sample.yaml +++ b/auction-server/config.sample.yaml @@ -4,3 +4,4 @@ chains: per_contract: 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 adapter_contract: 0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e legacy_tx: false + poll_interval: 1 diff --git a/auction-server/src/api.rs b/auction-server/src/api.rs index e3be2a8b..5e1202cc 100644 --- a/auction-server/src/api.rs +++ b/auction-server/src/api.rs @@ -188,7 +188,7 @@ pub async fn start_server(run_options: RunOptions) -> Result<()> { rpc_addr = chain_config.geth_rpc_addr ) })?; - provider.set_interval(Duration::from_secs(1)); + provider.set_interval(Duration::from_secs(chain_config.poll_interval)); let id = provider.get_chainid().await?.as_u64(); Ok(( chain_id.clone(), diff --git a/auction-server/src/config.rs b/auction-server/src/config.rs index e5ed0723..e2411dfb 100644 --- a/auction-server/src/config.rs +++ b/auction-server/src/config.rs @@ -77,6 +77,9 @@ pub struct EthereumConfig { /// URL of a Geth RPC endpoint to use for interacting with the blockchain. pub geth_rpc_addr: String, + /// Polling interval for event filters and pending transactions in seconds. + pub poll_interval: u64, + /// Address of the PER contract to interact with. pub per_contract: Address, From f12571b4923cb06a389cb65238314f255c7d124b Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sat, 3 Feb 2024 11:32:42 +0100 Subject: [PATCH 39/41] Temp serde --- auction-server/src/api/rest.rs | 21 +++++++++++++-------- auction-server/src/main.rs | 1 + auction-server/src/serde.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 auction-server/src/serde.rs diff --git a/auction-server/src/api/rest.rs b/auction-server/src/api/rest.rs index 9c0999b9..111e6568 100644 --- a/auction-server/src/api/rest.rs +++ b/auction-server/src/api/rest.rs @@ -32,6 +32,10 @@ use { utoipa::ToSchema, }; +#[derive(Clone, Debug, Deserialize, Serialize, ToSchema)] +#[schema(value_type=String)] +pub struct BidAmount(#[serde(with = "crate::serde::u256")] U256); + #[derive(Serialize, Deserialize, ToSchema, Clone)] pub struct Bid { /// The permission key to bid on. @@ -47,8 +51,7 @@ pub struct Bid { #[schema(example = "0xdeadbeef", value_type=String)] calldata: Bytes, /// Amount of bid in wei. - #[schema(example = "1000000000000000000")] - bid: String, + bid: BidAmount, } pub struct ParsedBid { @@ -117,21 +120,23 @@ pub async fn bid( State(store): State>, Json(bid): Json, ) -> Result { + let bid = bid.clone(); + tracing::info!("Received bid: {:?}", bid.bid); store .chains .get(&bid.chain_id) .ok_or(RestError::InvalidChainId)?; - let bid_amount = U256::from_dec_str(bid.bid.as_str()) - .map_err(|_| RestError::BadParameters("Invalid bid amount".to_string()))?; + // let bid_amount = U256::from_dec_str(bid.bid.as_str()) + // .map_err(|_| RestError::BadParameters("Invalid bid amount".to_string()))?; handle_bid( store, ParsedBid { permission_key: bid.permission_key, - chain_id: bid.chain_id, - contract: bid.contract, - calldata: bid.calldata, - bid_amount, + chain_id: bid.chain_id, + contract: bid.contract, + calldata: bid.calldata, + bid_amount: bid.bid.0, }, ) .await diff --git a/auction-server/src/main.rs b/auction-server/src/main.rs index d7492b4c..40a860f6 100644 --- a/auction-server/src/main.rs +++ b/auction-server/src/main.rs @@ -10,6 +10,7 @@ mod api; mod auction; mod config; mod liquidation_adapter; +mod serde; mod state; #[tokio::main] diff --git a/auction-server/src/serde.rs b/auction-server/src/serde.rs new file mode 100644 index 00000000..3bef9567 --- /dev/null +++ b/auction-server/src/serde.rs @@ -0,0 +1,29 @@ +pub mod u256 { + use { + ethers::types::U256, + serde::{ + de::{ + Error, + IntoDeserializer, + }, + Deserialize, + Deserializer, + Serializer, + }, + }; + + pub fn serialize(b: &U256, s: S) -> Result + where + S: Serializer, + { + s.serialize_str(b.to_string().as_str()) + } + + pub fn deserialize<'de, D>(d: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = Deserialize::deserialize(d)?; + U256::from_dec_str(s.as_str()).map_err(|err| D::Error::custom(err.to_string())) + } +} From 20c6e04267722fff84cd6e80d4d9ee861a59084a Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 4 Feb 2024 14:28:52 +0100 Subject: [PATCH 40/41] Direct parsing of U256 and Signature using serde custom module --- auction-server/src/api/marketplace.rs | 93 +++++++++-------------- auction-server/src/api/rest.rs | 45 +++-------- auction-server/src/liquidation_adapter.rs | 6 +- auction-server/src/serde.rs | 32 +++++++- per_sdk/searcher/simple_searcher.py | 4 +- 5 files changed, 79 insertions(+), 101 deletions(-) diff --git a/auction-server/src/api/marketplace.rs b/auction-server/src/api/marketplace.rs index c8066805..24a9031d 100644 --- a/auction-server/src/api/marketplace.rs +++ b/auction-server/src/api/marketplace.rs @@ -4,6 +4,7 @@ use { rest::handle_bid, RestError, }, + config::ChainId, liquidation_adapter::{ make_liquidator_calldata, parse_revert_error, @@ -26,10 +27,7 @@ use { Deserialize, Serialize, }, - std::{ - str::FromStr, - sync::Arc, - }, + std::sync::Arc, utoipa::ToSchema, uuid::Uuid, }; @@ -40,8 +38,9 @@ pub struct TokenQty { #[schema(example = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",value_type=String)] contract: Address, /// Token amount - #[schema(example = "1000")] - amount: String, + #[schema(example = "1000", value_type=String)] + #[serde(with = "crate::serde::u256")] + amount: U256, } /// A liquidation opportunity ready to be executed. @@ -55,7 +54,7 @@ pub struct LiquidationOpportunity { permission_key: Bytes, /// The chain id where the liquidation will be executed. #[schema(example = "sepolia")] - chain_id: String, + chain_id: ChainId, /// The contract address to call for execution of the liquidation. #[schema(example = "0xcA11bde05977b3631167028862bE2a173976CA11", value_type=String)] contract: Address, @@ -63,8 +62,9 @@ pub struct LiquidationOpportunity { #[schema(example = "0xdeadbeef", value_type=String)] calldata: Bytes, /// The value to send with the contract call. - #[schema(example = "1")] - value: String, + #[schema(example = "1", value_type=String)] + #[serde(with = "crate::serde::u256")] + value: U256, repay_tokens: Vec, receipt_tokens: Vec, @@ -84,23 +84,19 @@ impl From<(Address, U256)> for TokenQty { fn from(token: (Address, U256)) -> Self { TokenQty { contract: token.0, - amount: token.1.to_string(), + amount: token.1, } } } -impl TryFrom for (Address, U256) { - type Error = RestError; - - fn try_from(token: TokenQty) -> Result { - let amount = U256::from_dec_str(token.amount.as_str()) - .map_err(|_| RestError::BadParameters("Invalid token amount".to_string()))?; - Ok((token.contract, amount)) +impl From for (Address, U256) { + fn from(token: TokenQty) -> Self { + (token.contract, token.amount) } } -fn parse_tokens(tokens: Vec) -> Result, RestError> { - tokens.into_iter().map(|token| token.try_into()).collect() +fn parse_tokens(tokens: Vec) -> Vec<(Address, U256)> { + tokens.into_iter().map(|token| token.into()).collect() } /// Submit a liquidation opportunity ready to be executed. @@ -120,8 +116,8 @@ pub async fn submit_opportunity( .get(&opportunity.chain_id) .ok_or(RestError::InvalidChainId)?; - let repay_tokens = parse_tokens(opportunity.repay_tokens)?; - let receipt_tokens = parse_tokens(opportunity.receipt_tokens)?; + let repay_tokens = parse_tokens(opportunity.repay_tokens); + let receipt_tokens = parse_tokens(opportunity.receipt_tokens); //TODO: Verify if the call actually works @@ -134,8 +130,7 @@ pub async fn submit_opportunity( permission_key: opportunity.permission_key, contract: opportunity.contract, calldata: opportunity.calldata, - value: U256::from_dec_str(opportunity.value.as_str()) - .map_err(|_| RestError::BadParameters("Invalid value".to_string()))?, + value: opportunity.value, repay_tokens, receipt_tokens, }, @@ -166,7 +161,7 @@ pub async fn fetch_opportunities( chain_id: opportunity.chain_id, contract: opportunity.contract, calldata: opportunity.calldata, - value: opportunity.value.to_string(), + value: opportunity.value, repay_tokens: opportunity .repay_tokens .into_iter() @@ -188,31 +183,26 @@ pub async fn fetch_opportunities( pub struct OpportunityBid { /// The opportunity id to bid on. #[schema(example = "f47ac10b-58cc-4372-a567-0e02b2c3d479",value_type=String)] - opportunity_id: Uuid, + pub opportunity_id: Uuid, /// The opportunity permission key #[schema(example = "0xdeadbeefcafe", value_type=String)] - permission_key: Bytes, + pub permission_key: Bytes, /// The bid amount in wei. - #[schema(example = "1000000000000000000")] - bid_amount: String, + #[schema(example = "1000000000000000000", value_type=String)] + #[serde(with = "crate::serde::u256")] + pub amount: U256, /// How long the bid will be valid for. - #[schema(example = "1000000000000000000")] - valid_until: String, + #[schema(example = "1000000000000000000", value_type=String)] + #[serde(with = "crate::serde::u256")] + pub valid_until: U256, /// Liquidator address #[schema(example = "0x5FbDB2315678afecb367f032d93F642f64180aa2", value_type=String)] - liquidator: Address, + pub liquidator: Address, #[schema( - example = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12" + example = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12", + value_type=String )] - signature: String, -} - -#[derive(Clone, Copy)] -pub struct VerifiedOpportunityBid { - pub opportunity_id: Uuid, - pub bid_amount: U256, - pub valid_until: U256, - pub liquidator: Address, + #[serde(with = "crate::serde::signature")] pub signature: Signature, } @@ -242,23 +232,10 @@ pub async fn bid_opportunity( .get(&liquidation.chain_id) .ok_or(RestError::InvalidChainId)?; - let bid_amount = U256::from_dec_str(opportunity_bid.bid_amount.as_str()) - .map_err(|_| RestError::BadParameters("Invalid bid_amount".to_string()))?; - let valid_until = U256::from_dec_str(opportunity_bid.valid_until.as_str()) - .map_err(|_| RestError::BadParameters("Invalid valid_until".to_string()))?; - let signature = Signature::from_str(opportunity_bid.signature.as_str()) - .map_err(|_| RestError::BadParameters("Invalid signature".to_string()))?; - let verified_liquidation_bid = VerifiedOpportunityBid { - opportunity_id: opportunity_bid.opportunity_id, - bid_amount, - valid_until, - liquidator: opportunity_bid.liquidator, - signature, - }; - + let bid_amount = opportunity_bid.amount; let per_calldata = make_liquidator_calldata( liquidation.clone(), - verified_liquidation_bid, + opportunity_bid, chain_store.provider.clone(), chain_store.config.adapter_contract, ) @@ -266,12 +243,12 @@ pub async fn bid_opportunity( .map_err(|e| RestError::BadParameters(e.to_string()))?; match handle_bid( store.clone(), - crate::api::rest::ParsedBid { + crate::api::rest::Bid { permission_key: liquidation.permission_key.clone(), chain_id: liquidation.chain_id.clone(), contract: chain_store.config.adapter_contract, calldata: per_calldata, - bid_amount: verified_liquidation_bid.bid_amount, + amount: bid_amount, }, ) .await diff --git a/auction-server/src/api/rest.rs b/auction-server/src/api/rest.rs index 111e6568..4f6bf6a9 100644 --- a/auction-server/src/api/rest.rs +++ b/auction-server/src/api/rest.rs @@ -32,37 +32,27 @@ use { utoipa::ToSchema, }; -#[derive(Clone, Debug, Deserialize, Serialize, ToSchema)] -#[schema(value_type=String)] -pub struct BidAmount(#[serde(with = "crate::serde::u256")] U256); - #[derive(Serialize, Deserialize, ToSchema, Clone)] pub struct Bid { /// The permission key to bid on. #[schema(example = "0xdeadbeef", value_type=String)] - permission_key: Bytes, + pub permission_key: Bytes, /// The chain id to bid on. #[schema(example = "sepolia")] - chain_id: String, + pub chain_id: String, /// The contract address to call. #[schema(example = "0xcA11bde05977b3631167028862bE2a173976CA11",value_type = String)] - contract: Address, + pub contract: Address, /// Calldata for the contract call. #[schema(example = "0xdeadbeef", value_type=String)] - calldata: Bytes, - /// Amount of bid in wei. - bid: BidAmount, -} - -pub struct ParsedBid { - pub permission_key: Bytes, - pub chain_id: String, - pub contract: Address, pub calldata: Bytes, - pub bid_amount: U256, + /// Amount of bid in wei. + #[schema(example = "10", value_type=String)] + #[serde(with = "crate::serde::u256")] + pub amount: U256, } -pub async fn handle_bid(store: Arc, bid: ParsedBid) -> Result { +pub async fn handle_bid(store: Arc, bid: Bid) -> Result { let chain_store = store .chains .get(&bid.chain_id) @@ -74,7 +64,7 @@ pub async fn handle_bid(store: Arc, bid: ParsedBid) -> Result, bid: ParsedBid) -> Result, ) -> Result { let bid = bid.clone(); - tracing::info!("Received bid: {:?}", bid.bid); store .chains .get(&bid.chain_id) .ok_or(RestError::InvalidChainId)?; - // let bid_amount = U256::from_dec_str(bid.bid.as_str()) - // .map_err(|_| RestError::BadParameters("Invalid bid amount".to_string()))?; - handle_bid( - store, - ParsedBid { - permission_key: bid.permission_key, - chain_id: bid.chain_id, - contract: bid.contract, - calldata: bid.calldata, - bid_amount: bid.bid.0, - }, - ) - .await + handle_bid(store, bid).await } diff --git a/auction-server/src/liquidation_adapter.rs b/auction-server/src/liquidation_adapter.rs index aae0bce1..82155974 100644 --- a/auction-server/src/liquidation_adapter.rs +++ b/auction-server/src/liquidation_adapter.rs @@ -1,6 +1,6 @@ use { crate::{ - api::marketplace::VerifiedOpportunityBid, + api::marketplace::OpportunityBid, state::VerifiedLiquidationOpportunity, }, anyhow::{ @@ -96,7 +96,7 @@ pub fn parse_revert_error(revert: &Bytes) -> Option { pub async fn make_liquidator_calldata( opportunity: VerifiedLiquidationOpportunity, - bid: VerifiedOpportunityBid, + bid: OpportunityBid, provider: Provider, adapter_contract: Address, ) -> Result { @@ -116,7 +116,7 @@ pub async fn make_liquidator_calldata( data: opportunity.calldata, value: opportunity.value, valid_until: bid.valid_until, - bid: bid.bid_amount, + bid: bid.amount, signature_liquidator: bid.signature.to_vec().into(), }; let client = Arc::new(provider); diff --git a/auction-server/src/serde.rs b/auction-server/src/serde.rs index 3bef9567..001b6b77 100644 --- a/auction-server/src/serde.rs +++ b/auction-server/src/serde.rs @@ -2,10 +2,7 @@ pub mod u256 { use { ethers::types::U256, serde::{ - de::{ - Error, - IntoDeserializer, - }, + de::Error, Deserialize, Deserializer, Serializer, @@ -27,3 +24,30 @@ pub mod u256 { U256::from_dec_str(s.as_str()).map_err(|err| D::Error::custom(err.to_string())) } } +pub mod signature { + use { + ethers::types::Signature, + serde::{ + de::Error, + Deserialize, + Deserializer, + Serializer, + }, + std::str::FromStr, + }; + + pub fn serialize(b: &Signature, s: S) -> Result + where + S: Serializer, + { + s.serialize_str(b.to_string().as_str()) + } + + pub fn deserialize<'de, D>(d: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = Deserialize::deserialize(d)?; + Signature::from_str(s.as_str()).map_err(|err| D::Error::custom(err.to_string())) + } +} diff --git a/per_sdk/searcher/simple_searcher.py b/per_sdk/searcher/simple_searcher.py index 7196d6c4..0168b94d 100644 --- a/per_sdk/searcher/simple_searcher.py +++ b/per_sdk/searcher/simple_searcher.py @@ -45,7 +45,7 @@ def assess_liquidation_opportunity( class OpportunityBid(TypedDict): opportunity_id: str permission_key: str - bid_amount: str + amount: str valid_until: str liquidator: str signature: str @@ -86,7 +86,7 @@ def create_liquidation_transaction( opportunity_bid = { "opportunity_id": opp["opportunity_id"], "permission_key": opp["permission_key"], - "bid_amount": str(bid_info["bid"]), + "amount": str(bid_info["bid"]), "valid_until": str(bid_info["valid_until"]), "liquidator": liquidator, "signature": bytes(signature_liquidator.signature).hex(), From e3041a007597bd357fb3d0456317cf361e58ff5b Mon Sep 17 00:00:00 2001 From: Amin Moghaddam Date: Sun, 4 Feb 2024 14:33:58 +0100 Subject: [PATCH 41/41] Add comment on why token names are pricefeed ids --- per_multicall/script/Vault.s.sol | 1 + per_multicall/src/WETH9.sol | 1 + 2 files changed, 2 insertions(+) diff --git a/per_multicall/script/Vault.s.sol b/per_multicall/script/Vault.s.sol index d9a598c9..74e541e5 100644 --- a/per_multicall/script/Vault.s.sol +++ b/per_multicall/script/Vault.s.sol @@ -102,6 +102,7 @@ contract VaultScript is Script { address vault = deployVault(per, pyth); address[] memory tokens = new address[](5); uint256 lots_of_money = 10 ** 36; + // Vault simulator assumes the token name is pyth pricefeed id in mainnet tokens[0] = address( new MyToken( "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43", diff --git a/per_multicall/src/WETH9.sol b/per_multicall/src/WETH9.sol index c9972a27..ab03b478 100644 --- a/per_multicall/src/WETH9.sol +++ b/per_multicall/src/WETH9.sol @@ -20,6 +20,7 @@ pragma solidity ^0.8.0; contract WETH9 { + // Vault simulator assumes the token name is pyth pricefeed id in mainnet string public name = "c96458d393fe9deb7a7d63a0ac41e2898a67a7750dbd166673279e06c868df0a"; // ETH/USD pricefeed id string public symbol = "WETH";