diff --git a/.gitignore b/.gitignore index 852b72c5..eeea5289 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,17 @@ /rethdata monitoring/data-grafana/ monitoring/data-prometheus/ -/assets + +utils/logs/ + +# Foundry build artifacts +example/cache/ +example/out/ + +# Keep broadcast files except local dev chains and dry runs +example/broadcast/*/31337/ +example/broadcast/**/dry-run/ +assets .testnet .claude diff --git a/Cargo.lock b/Cargo.lock index 567b13a5..3248cf5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,9 +92,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.2.23" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35d744058a9daa51a8cf22a3009607498fcf82d3cf4c5444dd8056cdf651f471" +checksum = "25db5bcdd086f0b1b9610140a12c59b757397be90bd130d8d836fc8da0815a34" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -105,9 +105,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e318e25fb719e747a7e8db1654170fc185024f3ed5b10f86c08d448a912f6e2" +checksum = "f7ea09cffa9ad82f6404e6ab415ea0c41a7674c0f2e2e689cb8683f772b5940d" dependencies = [ "alloy-eips", "alloy-primitives", @@ -132,9 +132,9 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "364380a845193a317bcb7a5398fc86cdb66c47ebe010771dde05f6869bf9e64a" +checksum = "8aafa1f0ddb5cbb6cba6b10e8fa6e31f8c5d5c22e262b30a5d2fa9d336c3b637" dependencies = [ "alloy-consensus", "alloy-eips", @@ -146,9 +146,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d39c80ffc806f27a76ed42f3351a455f3dc4f81d6ff92c8aad2cf36b7d3a34" +checksum = "398c81368b864fdea950071a00b298c22b21506fed1ed8abc7f2902727f987f1" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -168,9 +168,9 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d48a9101f4a67c22fae57489f1ddf3057b8ab4a368d8eac3be088b6e9d9c9d9" +checksum = "369f5707b958927176265e8a58627fc6195e5dfa5c55689396e68b241b3a72e6" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -223,9 +223,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c4d7c5839d9f3a467900c625416b24328450c65702eb3d8caff8813e4d1d33" +checksum = "691fed81bbafefae0f5a6cedd837ebb3fade46e7d91c5b67a463af12ecf5b11a" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -254,7 +254,7 @@ checksum = "527b47dc39850c6168002ddc1f7a2063e15d26137c1bb5330f6065a7524c1aa9" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-hardforks 0.4.5", + "alloy-hardforks 0.4.7", "alloy-primitives", "alloy-rpc-types-engine", "alloy-rpc-types-eth", @@ -270,9 +270,9 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba4b1be0988c11f0095a2380aa596e35533276b8fa6c9e06961bbfe0aebcac5" +checksum = "bf91e325928dfffe90c769c2c758cc6e9ba35331c6e984310fe8276548df4a9e" dependencies = [ "alloy-eips", "alloy-primitives", @@ -298,9 +298,9 @@ dependencies = [ [[package]] name = "alloy-hardforks" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9a33550fc21fd77a3f8b63e99969d17660eec8dcc50a95a80f7c9964f7680b" +checksum = "83ba208044232d14d4adbfa77e57d6329f51bc1acc21f5667bb7db72d88a0831" dependencies = [ "alloy-chains", "alloy-eip2124", @@ -311,9 +311,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9914c147bb9b25f440eca68a31dc29f5c22298bfa7754aa802965695384122b0" +checksum = "84e3cf01219c966f95a460c95f1d4c30e12f6c18150c21a30b768af2a2a29142" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -323,9 +323,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f72cf87cda808e593381fb9f005ffa4d2475552b7a6c5ac33d087bf77d82abd0" +checksum = "8618cd8431d82d21ed98c300b6072f73fe925dff73b548aa2d4573b5a8d3ca91" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -338,9 +338,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12aeb37b6f2e61b93b1c3d34d01ee720207c76fe447e2a2c217e433ac75b17f5" +checksum = "390641d0e7e51d5d39b905be654ef391a89d62b9e6d3a74fd931b4df26daae20" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -364,9 +364,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abd29ace62872083e30929cd9b282d82723196d196db589f3ceda67edcc05552" +checksum = "9badd9de9f310f0c17602c642c043eee40033c0651f45809189e411f6b166e0f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -377,9 +377,9 @@ dependencies = [ [[package]] name = "alloy-node-bindings" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b000c0790644bd4effe719f4272f0023167567ca9534e4e071f6f18c4f7e44" +checksum = "6b08af28974d3f45b0b71c2203d9bc743ac801cb52ceb6bc827e450bf531b918" dependencies = [ "alloy-genesis", "alloy-hardforks 0.2.13", @@ -388,6 +388,7 @@ dependencies = [ "alloy-signer", "alloy-signer-local", "k256", + "libc", "rand 0.8.5", "serde_json", "tempfile", @@ -398,9 +399,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db950a29746be9e2f2c6288c8bd7a6202a81f999ce109a2933d2379970ec0fa" +checksum = "f6a0fb18dd5fb43ec5f0f6a20be1ce0287c79825827de5744afaa6c957737c33" dependencies = [ "alloy-rlp", "bytes", @@ -410,7 +411,7 @@ dependencies = [ "foldhash 0.2.0", "getrandom 0.3.4", "hashbrown 0.16.1", - "indexmap 2.12.1", + "indexmap 2.13.0", "itoa", "k256", "keccak-asm", @@ -427,9 +428,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b710636d7126e08003b8217e24c09f0cca0b46d62f650a841736891b1ed1fc1" +checksum = "3b7dcf6452993e31ea728b9fc316ebe4e4e3a820c094f2aad55646041ee812a0" dependencies = [ "alloy-chains", "alloy-consensus", @@ -451,7 +452,7 @@ dependencies = [ "either", "futures", "futures-utils-wasm", - "lru 0.13.0", + "lru 0.16.3", "parking_lot", "pin-project", "reqwest", @@ -483,14 +484,14 @@ checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "alloy-rpc-client" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0882e72d2c1c0c79dcf4ab60a67472d3f009a949f774d4c17d0bdb669cfde05" +checksum = "ce4a28b1302733f565a2900a0d7cb3db94ffd1dd58ad7ebf5b0ec302e868ed1e" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -511,9 +512,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cf1398cb33aacb139a960fa3d8cf8b1202079f320e77e952a0b95967bf7a9f" +checksum = "1408505e2a41c71f7b3f83ee52e5ecd0f2a6f2db98046d0a4defb9f85a007a9e" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -523,9 +524,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a63fb40ed24e4c92505f488f9dd256e2afaed17faa1b7a221086ebba74f4122" +checksum = "6792425a4a8e74be38e8785f90f497f8f325188f40f13c168a220310fd421d12" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -534,9 +535,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c60bdce3be295924122732b7ecd0b2495ce4790bedc5370ca7019c08ad3f26e" +checksum = "c7bcd9ead89076095806364327a1b18c2215998b6fff5a45f82c658bfbabf2df" dependencies = [ "alloy-consensus", "alloy-eips", @@ -554,9 +555,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eae0c7c40da20684548cbc8577b6b7447f7bf4ddbac363df95e3da220e41e72" +checksum = "a3b505d6223c88023fb1217ac24eab950e4368f6634405bea3977d34cae6935b" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -575,9 +576,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecb5a795264a02222f9534435b8f40dcbd88de8e9d586647884aae24f389ebf2" +checksum = "e14194567368b8c8b7aeef470831bbe90cc8b12ef5f48b18acdda9cf20070ff1" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -587,9 +588,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0df1987ed0ff2d0159d76b52e7ddfc4e4fbddacc54d2fbee765e0d14d7c01b5" +checksum = "75a755a3cc0297683c2879bbfe2ff22778f35068f07444f0b52b5b87570142b6" dependencies = [ "alloy-primitives", "serde", @@ -598,9 +599,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff69deedee7232d7ce5330259025b868c5e6a52fa8dffda2c861fb3a5889b24" +checksum = "9d73afcd1fb2d851bf4ba67504a951b73231596f819cc814f50d11126db7ac1b" dependencies = [ "alloy-primitives", "async-trait", @@ -613,9 +614,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72cfe0be3ec5a8c1a46b2e5a7047ed41121d360d97f4405bb7c1c784880c86cb" +checksum = "807b043936012acc788c96cba06b8580609d124bb105dc470a1617051cc4aa63" dependencies = [ "alloy-consensus", "alloy-network", @@ -633,42 +634,42 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b96d5f5890605ba9907ce1e2158e2701587631dc005bfa582cf92dd6f21147" +checksum = "09eb18ce0df92b4277291bbaa0ed70545d78b02948df756bbd3d6214bf39a218" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "alloy-sol-macro-expander" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8247b7cca5cde556e93f8b3882b01dbd272f527836049083d240c57bf7b4c15" +checksum = "95d9fa2daf21f59aa546d549943f10b5cce1ae59986774019fbedae834ffe01b" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", "const-hex", "heck", - "indexmap 2.12.1", + "indexmap 2.13.0", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "syn-solidity", "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd54f38512ac7bae10bbc38480eefb1b9b398ca2ce25db9cc0c048c6411c4f1" +checksum = "9396007fe69c26ee118a19f4dee1f5d1d6be186ea75b3881adf16d87f8444686" dependencies = [ "alloy-json-abi", "const-hex", @@ -678,15 +679,15 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.111", + "syn 2.0.114", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444b09815b44899564566d4d56613d14fa9a274b1043a021f00468568752f449" +checksum = "af67a0b0dcebe14244fc92002cd8d96ecbf65db4639d479f5fcd5805755a4c27" dependencies = [ "serde", "winnow", @@ -694,9 +695,9 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1038284171df8bfd48befc0c7b78f667a7e2be162f45f07bd1c378078ebe58" +checksum = "09aeea64f09a7483bdcd4193634c7e5cf9fd7775ee767585270cd8ce2d69dc95" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -706,9 +707,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be98b07210d24acf5b793c99b759e9a696e4a2e67593aec0487ae3b3e1a2478c" +checksum = "9b84a605484a03959436e5bea194e6d62f77c3caef750196b4b4f1c8d23254df" dependencies = [ "alloy-json-rpc", "auto_impl", @@ -729,9 +730,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4198a1ee82e562cab85e7f3d5921aab725d9bd154b6ad5017f82df1695877c97" +checksum = "1a400ad5b73590a099111481d4a66a2ca1266ebc85972a844958caf42bfdd37d" dependencies = [ "alloy-json-rpc", "alloy-rpc-types-engine", @@ -741,18 +742,21 @@ dependencies = [ "hyper-tls", "hyper-util", "jsonwebtoken", + "opentelemetry", + "opentelemetry-http", "reqwest", "serde_json", "tower", "tracing", + "tracing-opentelemetry", "url", ] [[package]] name = "alloy-trie" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3412d52bb97c6c6cc27ccc28d4e6e8cf605469101193b50b0bd5813b1f990b5" +checksum = "428aa0f0e0658ff091f8f667c406e034b431cb10abd39de4f507520968acc499" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -766,14 +770,14 @@ dependencies = [ [[package]] name = "alloy-tx-macros" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "333544408503f42d7d3792bfc0f7218b643d968a03d2c0ed383ae558fb4a76d0" +checksum = "f17272de4df6b8b59889b264f0306eba47a69f23f57f1c08f1366a4617b48c30" dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -852,7 +856,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -985,7 +989,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1023,7 +1027,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1112,7 +1116,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1184,7 +1188,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "synstructure", ] @@ -1196,7 +1200,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1243,7 +1247,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1265,7 +1269,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1276,7 +1280,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1328,7 +1332,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1449,9 +1453,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.1" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bech32" @@ -1577,7 +1581,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1600,7 +1604,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -1672,7 +1676,7 @@ checksum = "9988519e5f642c7ea3db4b6a31a50667ec61a26344e9c0bce3f8124931d8bb3f" dependencies = [ "bitvec", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "rand 0.8.5", ] @@ -1687,9 +1691,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.50" +version = "1.2.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f50d563227a1c37cc0a263f64eca3334388c01c5e4c4861a9def205c614383c" +checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" dependencies = [ "find-msvc-tools", "jobserver", @@ -1766,9 +1770,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.53" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" dependencies = [ "clap_builder", "clap_derive", @@ -1776,9 +1780,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.53" +version = "4.5.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" dependencies = [ "anstream", "anstyle", @@ -1795,14 +1799,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "clap_lex" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" [[package]] name = "coins-bip32" @@ -2142,7 +2146,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2189,7 +2193,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2204,7 +2208,7 @@ dependencies = [ "quote", "serde", "strsim", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2215,7 +2219,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2226,7 +2230,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2245,15 +2249,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "data-encoding-macro" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47ce6c96ea0102f01122a185683611bd5ac8d99e62bc59dd12e6bda344ee673d" +checksum = "8142a83c17aa9461d637e649271eae18bf2edd00e91f2e105df36c3c16355bdb" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -2261,12 +2265,12 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" +checksum = "7ab67060fc6b8ef687992d439ca0fa36e7ed17e9a0b16b25b601e8757df720de" dependencies = [ "data-encoding", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2323,29 +2327,29 @@ checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "derive_more" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.111", + "syn 2.0.114", "unicode-xid", ] @@ -2399,14 +2403,14 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "dtoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" [[package]] name = "dunce" @@ -2483,7 +2487,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2595,6 +2599,7 @@ dependencies = [ "reth-transaction-pool", "serde", "serde_json", + "serde_yaml", "tempfile", "test-log", "thiserror 2.0.17", @@ -2614,7 +2619,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2634,7 +2639,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2733,7 +2738,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -2813,9 +2818,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" [[package]] name = "fixed-hash" @@ -2960,7 +2965,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3044,9 +3049,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -3114,9 +3119,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", @@ -3124,7 +3129,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.12.1", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -3169,6 +3174,8 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ + "allocator-api2", + "equivalent", "foldhash 0.2.0", "serde", "serde_core", @@ -3632,7 +3639,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -3673,9 +3680,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -4006,9 +4013,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" dependencies = [ "memchr", "serde", @@ -4049,9 +4056,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jni" @@ -4209,9 +4216,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.178" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libm" @@ -4229,7 +4236,7 @@ dependencies = [ "either", "futures", "futures-timer", - "getrandom 0.2.16", + "getrandom 0.2.17", "libp2p-allow-block-list", "libp2p-connection-limits", "libp2p-core", @@ -4278,9 +4285,9 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.43.1" +version = "0.43.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d28e2d2def7c344170f5c6450c0dbe3dfef655610dbfde2f6ac28a527abbe36" +checksum = "249128cd37a2199aff30a7675dffa51caf073b51aa612d2f544b19932b9aebca" dependencies = [ "either", "fnv", @@ -4332,7 +4339,7 @@ dependencies = [ "fnv", "futures", "futures-timer", - "getrandom 0.2.16", + "getrandom 0.2.17", "hashlink", "hex_fmt", "libp2p-core", @@ -4584,7 +4591,7 @@ checksum = "dd297cf53f0cb3dee4d2620bb319ae47ef27c702684309f682bdb7e55a18ae9c" dependencies = [ "heck", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4654,9 +4661,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ "bitflags 2.10.0", "libc", @@ -4700,11 +4707,11 @@ dependencies = [ [[package]] name = "lru" -version = "0.13.0" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" +checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" dependencies = [ - "hashbrown 0.15.5", + "hashbrown 0.16.1", ] [[package]] @@ -4721,7 +4728,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4861,7 +4868,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -4919,9 +4926,9 @@ dependencies = [ [[package]] name = "moka" -version = "0.12.11" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8261cd88c312e0004c1d51baad2980c66528dfdb2bee62003e643a4d8f86b077" +checksum = "a3dec6bd31b08944e08b58fd99373893a6c17054d6f3ea5006cc894f4f4eee2a" dependencies = [ "crossbeam-channel", "crossbeam-epoch", @@ -4929,7 +4936,6 @@ dependencies = [ "equivalent", "parking_lot", "portable-atomic", - "rustc_version 0.4.1", "smallvec", "tagptr", "uuid 1.19.0", @@ -5006,7 +5012,7 @@ dependencies = [ "libc", "log", "openssl", - "openssl-probe", + "openssl-probe 0.1.6", "openssl-sys", "schannel", "security-framework 2.11.1", @@ -5223,14 +5229,14 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "nybbles" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4b5ecbd0beec843101bffe848217f770e8b8da81d8355b7d6e226f2199b3dc" +checksum = "7b5676b5c379cf5b03da1df2b3061c4a4e2aa691086a56ac923e08c143f53f59" dependencies = [ "alloy-rlp", "cfg-if", @@ -5349,7 +5355,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5358,6 +5364,12 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "openssl-probe" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" + [[package]] name = "openssl-src" version = "300.5.4+3.5.4" @@ -5380,6 +5392,32 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "opentelemetry" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.17", + "tracing", +] + +[[package]] +name = "opentelemetry-http" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" +dependencies = [ + "async-trait", + "bytes", + "http", + "opentelemetry", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -5429,7 +5467,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5519,9 +5557,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.4" +version = "2.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" +checksum = "2c9eb05c21a464ea704b53158d358a31e6425db2f63a1a7312268b05fe2b75f7" dependencies = [ "memchr", "ucd-trie", @@ -5534,7 +5572,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset", - "indexmap 2.12.1", + "indexmap 2.13.0", ] [[package]] @@ -5568,7 +5606,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5597,7 +5635,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5667,9 +5705,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f59e70c4aef1e55797c2e8fd94a4f2a973fc972cfde0e0b05f683667b0cd39dd" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" [[package]] name = "potential_utf" @@ -5702,7 +5740,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5753,14 +5791,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" dependencies = [ "unicode-ident", ] @@ -5785,7 +5823,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5833,7 +5871,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.111", + "syn 2.0.114", "tempfile", ] @@ -5847,7 +5885,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -5945,9 +5983,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.42" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] @@ -5999,7 +6037,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", "serde", ] @@ -6020,7 +6058,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -6029,14 +6067,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", "serde", @@ -6048,14 +6086,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] name = "rapidhash" -version = "4.1.1" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e65c75143ce5d47c55b510297eeb1182f3c739b6043c537670e9fc18612dae" +checksum = "5d8b5b858a440a0bc02625b62dd95131b9201aa9f69f411195dd4a7cfb1de3d7" dependencies = [ "rand 0.9.2", "rustversion", @@ -6118,7 +6156,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "libredox", "thiserror 1.0.69", ] @@ -6140,7 +6178,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -6174,9 +6212,9 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" -version = "0.12.26" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", "bytes", @@ -6294,7 +6332,7 @@ source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea8 dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -6339,7 +6377,7 @@ dependencies = [ "alloy-chains", "alloy-consensus", "alloy-eips", - "alloy-hardforks 0.4.5", + "alloy-hardforks 0.4.7", "alloy-primitives", "alloy-rlp", "bytes", @@ -6358,7 +6396,7 @@ version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ "alloy-eip2124", - "alloy-hardforks 0.4.5", + "alloy-hardforks 0.4.7", "alloy-primitives", "auto_impl", "once_cell", @@ -6882,7 +6920,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -6939,9 +6977,9 @@ dependencies = [ [[package]] name = "ruint" -version = "1.17.0" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" +checksum = "c141e807189ad38a07276942c6623032d3753c8859c146104ac2e4d68865945a" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", @@ -7021,9 +7059,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ "bitflags 2.10.0", "errno", @@ -7034,9 +7072,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.35" +version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ "log", "once_cell", @@ -7049,11 +7087,11 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe", + "openssl-probe 0.2.0", "rustls-pki-types", "schannel", "security-framework 3.5.1", @@ -7138,9 +7176,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" [[package]] name = "salsa20" @@ -7183,9 +7221,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" +checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" dependencies = [ "dyn-clone", "ref-cast", @@ -7371,21 +7409,21 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -7430,9 +7468,9 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.12.1", + "indexmap 2.13.0", "schemars 0.9.0", - "schemars 1.1.0", + "schemars 1.2.0", "serde_core", "serde_json", "serde_with_macros", @@ -7448,7 +7486,20 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.13.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", ] [[package]] @@ -7522,10 +7573,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.7" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -7671,7 +7723,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7683,7 +7735,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7711,9 +7763,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.111" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -7722,14 +7774,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6b1d2e2059056b66fec4a6bb2b79511d5e8d76196ef49c38996f4b48db7662f" +checksum = "5f92d01b5de07eaf324f7fca61cc6bd3d82bbc1de5b6c963e6fe79e86f36580d" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7749,7 +7801,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7787,9 +7839,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.23.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ "fastrand", "getrandom 0.3.4", @@ -7817,7 +7869,7 @@ checksum = "be35209fd0781c5401458ab66e4f98accf63553e8fae7425503e92fdd319783b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7846,7 +7898,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7857,7 +7909,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7880,30 +7932,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" dependencies = [ "num-conv", "time-core", @@ -7945,9 +7997,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.48.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ "bytes", "libc", @@ -7969,7 +8021,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -7994,9 +8046,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -8006,9 +8058,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.17" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -8053,7 +8105,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "serde", "serde_spanned", "toml_datetime 0.6.11", @@ -8067,7 +8119,7 @@ version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "winnow", @@ -8090,9 +8142,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -8166,7 +8218,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -8210,6 +8262,22 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-opentelemetry" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac28f2d093c6c477eaa76b23525478f38de514fa9aeb1285738d4b97a9552fc" +dependencies = [ + "js-sys", + "opentelemetry", + "smallvec", + "tracing", + "tracing-core", + "tracing-log", + "tracing-subscriber 0.3.22", + "web-time", +] + [[package]] name = "tracing-serde" version = "0.2.0" @@ -8326,6 +8394,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "unsigned-varint" version = "0.7.2" @@ -8346,9 +8420,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", @@ -8374,7 +8448,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "serde", ] @@ -8495,7 +8569,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "wasm-bindgen-shared", ] @@ -8561,23 +8635,23 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" dependencies = [ - "webpki-root-certs 1.0.4", + "webpki-root-certs 1.0.5", ] [[package]] name = "webpki-root-certs" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3e3b5f5e80bc89f30ce8d0343bf4e5f12341c51f3e26cbeecbc7c85443e85b" +checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" dependencies = [ "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" +checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" dependencies = [ "rustls-pki-types", ] @@ -8660,7 +8734,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -8671,7 +8745,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -9158,28 +9232,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -9199,7 +9273,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", "synstructure", ] @@ -9214,13 +9288,13 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] [[package]] @@ -9253,9 +9327,15 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.114", ] +[[package]] +name = "zmij" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" + [[package]] name = "zstd" version = "0.13.3" diff --git a/solidity/foundry.lock b/solidity/foundry.lock index 56437fc9..ea545c01 100644 --- a/solidity/foundry.lock +++ b/solidity/foundry.lock @@ -11,4 +11,4 @@ "rev": "c64a1edb67b6e3f4a15cca8909c9482ad33a02b0" } } -} +} \ No newline at end of file diff --git a/utils/Cargo.toml b/utils/Cargo.toml index a057467f..de23fbd1 100644 --- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -16,8 +16,9 @@ color-eyre = { workspace = true } tokio = { version = "1", features = [ "full" ] } serde = { version = "1", features = [ "derive" ] } serde_json = "1" -tracing = "0.1" -tracing-subscriber = "0.3" +serde_yaml = "0.9.33" +tracing = { workspace = true } +tracing-subscriber = { workspace = true } async-trait = "0.1" hex = "0.4" clap = { version = "4.5", features = [ "derive" ] } diff --git a/utils/examples/exchange_transactions.yaml b/utils/examples/exchange_transactions.yaml new file mode 100644 index 00000000..77aaaf78 --- /dev/null +++ b/utils/examples/exchange_transactions.yaml @@ -0,0 +1,177 @@ +# Exchange DEX Transaction Templates +# +# This file contains transaction templates for testing the Exchange.sol DEX contract. +# The transactions cycle through price initialization, sell orders, and buy orders +# to simulate realistic trading activity and stress test the order matching engine. +# +# Based on: foundry-backend/quick_test.sh +# +# Contract Addresses (from deployment): +# Exchange: 0xD8E47743AC7C5eaE9A8e0C570b91A28FdB3f8F71 +# ETH Token (tokenA): 0x419e6594AFb029A41fDF986964CcEE8aDeE141b7 +# USDb Token (tokenB): 0xb2ea407e360d2f5C5F327cDcC38182Bd2e7FFeCa +# +# IMPORTANT Prerequisites: +# 1. Approve Exchange contract to spend both tokens (using WALLET_PRIVATE_KEY_1): +# cast send 0x419e6594AFb029A41fDF986964CcEE8aDeE141b7 \ +# "approve(address,uint256)" 0xD8E47743AC7C5eaE9A8e0C570b91A28FdB3f8F71 \ +# $(cast max-uint) --private-key $WALLET_PRIVATE_KEY_1 --rpc-url http://127.0.0.1:8545 +# cast send 0xb2ea407e360d2f5C5F327cDcC38182Bd2e7FFeCa \ +# "approve(address,uint256)" 0xD8E47743AC7C5eaE9A8e0C570b91A28FdB3f8F71 \ +# $(cast max-uint) --private-key $WALLET_PRIVATE_KEY_1 --rpc-url http://127.0.0.1:8545 +# +# 2. Ensure signer has sufficient token balances +# +# 3. Price Index Limitation: +# The priceIdx parameter in sell/buy orders MUST match the actual index returned by +# Exchange.getIndexOfPrice(price). This template assumes: +# - Price 1500 is at index 0 (initialized first) +# - No other prices exist in the order book +# +# If prices are initialized in a different order, or other prices already exist, +# the priceIdx values will be incorrect and transactions will revert with: +# "Price does not match the index" +# +# To verify correct indices, run: +# cast call $EXCHANGE "getIndexOfPrice(uint32)" 1500 --rpc-url http://127.0.0.1:8545 + +transactions: + # Transaction 1: Initialize price level 1500 + # Function: initPVnode(uint32 price) + # Selector: 0x1cfe8740 + # Parameters: price = 1500 (0x05dc) + # From quick_test.sh line 51: cast send $EXCHANGE "initPVnode(uint32)" 1500 + # Will succeed on first run, then revert with "Price already exist in orderbook" + - type: eip1559 + to: "0xD8E47743AC7C5eaE9A8e0C570b91A28FdB3f8F71" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "5" + max_priority_fee_per_gas: "2" + input: "0x1cfe874000000000000000000000000000000000000000000000000000000000000005dc" + + # Transaction 2: Place sell order - 50 ETH @ price 1500 (index 0) + # Function: newSellOrder(uint32 price, uint256 sellAmount, uint256 priceIdx) + # Selector: 0x4cc4b233 + # Parameters: price=1500 (0x05dc), sellAmount=50000000 (50M = 50 tokens with 6 decimals), priceIdx=0 + # From quick_test.sh line 76: cast send $EXCHANGE "newSellOrder(uint32,uint256,uint256)" 1500 50000000 $PRICE_INDEX_DEC + - type: eip1559 + to: "0xD8E47743AC7C5eaE9A8e0C570b91A28FdB3f8F71" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "5" + max_priority_fee_per_gas: "2" + input: "0x4cc4b23300000000000000000000000000000000000000000000000000000000000005dc0000000000000000000000000000000000000000000000000000000002faf0800000000000000000000000000000000000000000000000000000000000000000" + + # Transaction 3: Place buy order - 25 ETH @ price 1500 (index 0) + # Function: newBuyOrder(uint32 price, uint256 buyAmount, uint256 priceIdx) + # Selector: 0xd1a6e82c + # Parameters: price=1500 (0x05dc), buyAmount=25000000 (25M = 25 tokens with 6 decimals), priceIdx=0 + # From quick_test.sh line 82: cast send $EXCHANGE "newBuyOrder(uint32,uint256,uint256)" 1500 25000000 $PRICE_INDEX_DEC + # This will match with the sell order above, executing a trade + - type: eip1559 + to: "0xD8E47743AC7C5eaE9A8e0C570b91A28FdB3f8F71" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "5" + max_priority_fee_per_gas: "2" + input: "0xd1a6e82c00000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000017d78400000000000000000000000000000000000000000000000000000000000000000" + + # Transaction 2: Place sell order - 50 ETH @ price 1500 (index 0) + # Function: newSellOrder(uint32 price, uint256 sellAmount, uint256 priceIdx) + # Selector: 0x4cc4b233 + # Parameters: price=1500 (0x05dc), sellAmount=50000000 (50M = 50 tokens with 6 decimals), priceIdx=0 + # From quick_test.sh line 76: cast send $EXCHANGE "newSellOrder(uint32,uint256,uint256)" 1500 50000000 $PRICE_INDEX_DEC + - type: eip1559 + to: "0xD8E47743AC7C5eaE9A8e0C570b91A28FdB3f8F71" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "5" + max_priority_fee_per_gas: "2" + input: "0x4cc4b23300000000000000000000000000000000000000000000000000000000000005dc0000000000000000000000000000000000000000000000000000000002faf0800000000000000000000000000000000000000000000000000000000000000000" + + # Transaction 3: Place buy order - 25 ETH @ price 1500 (index 0) + # Function: newBuyOrder(uint32 price, uint256 buyAmount, uint256 priceIdx) + # Selector: 0xd1a6e82c + # Parameters: price=1500 (0x05dc), buyAmount=25000000 (25M = 25 tokens with 6 decimals), priceIdx=0 + # From quick_test.sh line 82: cast send $EXCHANGE "newBuyOrder(uint32,uint256,uint256)" 1500 25000000 $PRICE_INDEX_DEC + # This will match with the sell order above, executing a trade + - type: eip1559 + to: "0xD8E47743AC7C5eaE9A8e0C570b91A28FdB3f8F71" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "5" + max_priority_fee_per_gas: "2" + input: "0xd1a6e82c00000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000017d78400000000000000000000000000000000000000000000000000000000000000000" + # Transaction 3: Place buy order - 25 ETH @ price 1500 (index 0) + # Function: newBuyOrder(uint32 price, uint256 buyAmount, uint256 priceIdx) + # Selector: 0xd1a6e82c + # Parameters: price=1500 (0x05dc), buyAmount=25000000 (25M = 25 tokens with 6 decimals), priceIdx=0 + # From quick_test.sh line 82: cast send $EXCHANGE "newBuyOrder(uint32,uint256,uint256)" 1500 25000000 $PRICE_INDEX_DEC + # This will match with the sell order above, executing a trade + - type: eip1559 + to: "0xD8E47743AC7C5eaE9A8e0C570b91A28FdB3f8F71" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "5" + max_priority_fee_per_gas: "2" + input: "0xd1a6e82c00000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000017d78400000000000000000000000000000000000000000000000000000000000000000" + # Transaction 3: Place buy order - 25 ETH @ price 1500 (index 0) + # Function: newBuyOrder(uint32 price, uint256 buyAmount, uint256 priceIdx) + # Selector: 0xd1a6e82c + # Parameters: price=1500 (0x05dc), buyAmount=25000000 (25M = 25 tokens with 6 decimals), priceIdx=0 + # From quick_test.sh line 82: cast send $EXCHANGE "newBuyOrder(uint32,uint256,uint256)" 1500 25000000 $PRICE_INDEX_DEC + # This will match with the sell order above, executing a trade + - type: eip1559 + to: "0xD8E47743AC7C5eaE9A8e0C570b91A28FdB3f8F71" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "5" + max_priority_fee_per_gas: "2" + input: "0xd1a6e82c00000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000017d78400000000000000000000000000000000000000000000000000000000000000000" + # Transaction 2: Place sell order - 50 ETH @ price 1500 (index 0) + # Function: newSellOrder(uint32 price, uint256 sellAmount, uint256 priceIdx) + # Selector: 0x4cc4b233 + # Parameters: price=1500 (0x05dc), sellAmount=50000000 (50M = 50 tokens with 6 decimals), priceIdx=0 + # From quick_test.sh line 76: cast send $EXCHANGE "newSellOrder(uint32,uint256,uint256)" 1500 50000000 $PRICE_INDEX_DEC + - type: eip1559 + to: "0xD8E47743AC7C5eaE9A8e0C570b91A28FdB3f8F71" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "5" + max_priority_fee_per_gas: "2" + input: "0x4cc4b23300000000000000000000000000000000000000000000000000000000000005dc0000000000000000000000000000000000000000000000000000000002faf0800000000000000000000000000000000000000000000000000000000000000000" + + +# Usage Example: +# +# 1. First, ensure you have run the approvals (see Prerequisites section above) +# +# 2. Run the spammer with --dex flag: +# cargo run --bin malachitebft-eth-utils -- spam \ +# --dex \ +# --rate 10 \ +# --num-txs 30 \ +# --rpc-url 127.0.0.1:8545 \ +# --signer-index 0 +# +# This will spam the Exchange contract with 30 transactions at 10 tx/s, +# cycling through the 3 transaction templates in round-robin fashion: +# initPVnode -> newSellOrder -> newBuyOrder -> initPVnode -> newSellOrder -> ... +# +# Expected behavior (matches quick_test.sh flow): +# - First initPVnode(1500) will succeed and create price at index 0 +# - Subsequent initPVnode(1500) calls will fail with "Price already exist in orderbook" +# - newSellOrder transactions will place 50 ETH sell orders at price 1500 +# - newBuyOrder transactions will place 25 ETH buy orders and trigger matching +# - Each buy order will partially match with a sell order, executing a trade +# - After matching, 25 ETH of the sell order is filled, leaving 25 ETH remaining +# - Fees accumulate in the Exchange contract (0.1% per trade, feeRate=999) +# +# Troubleshooting: +# - If transactions fail with "Price does not match the index": +# Verify the price index with: cast call $EXCHANGE "getIndexOfPrice(uint32)" 1500 +# - If transactions fail with "ERC20: insufficient allowance": +# Run the approval commands from Prerequisites section +# - If transactions fail with "ERC20: transfer amount exceeds balance": +# Ensure the signer has sufficient ETH token and USDb token balances diff --git a/utils/examples/generated_dexalot.yaml b/utils/examples/generated_dexalot.yaml new file mode 100644 index 00000000..db74892e --- /dev/null +++ b/utils/examples/generated_dexalot.yaml @@ -0,0 +1,148 @@ +transactions: +- type: eip1559 + to: 0x0e801d84fa97b50751dbf25036d067dcf18858bf + value: '11' + gas_limit: 200000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0x4ae67c59000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000000 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b298415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c93a592cfb2a00000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b299415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ca9d9ea558b4000000000000000000000000000000000000000000000000000014d1120d7b160000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b29a415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cc00e41db63e00000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b29b415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd64299613c8000000000000000000000000000000000000000000000000000010a741a462780000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b29c415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cec76f0e715200000000000000000000000000000000000000000000000000000c7d713b49da0000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b29d415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d02ab486cedc00000000000000000000000000000000000000000000000000000f43fc2c04ee0000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b29e415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d18df9ff2c66000000000000000000000000000000000000000000000000000009b6e64a8ec60000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b29f415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d2f13f7789f00000000000000000000000000000000000000000000000000000120a871cc0020000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b2a0415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d45484efe77a00000000000000000000000000000000000000000000000000000d2f13f7789f0000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b2a1415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5b7ca68450400000000000000000000000000000000000000000000000000000e92596fd6290000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b2fc415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d02ab486cedc00000000000000000000000000000000000000000000000000000853a0d2313c0000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b2fd415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d18df9ff2c6600000000000000000000000000000000000000000000000000000a688906bd8b0000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b2fe415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d2f13f7789f0000000000000000000000000000000000000000000000000000006f05b59d3b20000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b2ff415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d45484efe77a00000000000000000000000000000000000000000000000000000bcbce7f1b150000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b300415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5b7ca68450400000000000000000000000000000000000000000000000000000905438e60010000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b301415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d71b0fe0a28e000000000000000000000000000000000000000000000000000007a1fe1602770000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b302415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d87e55590018000000000000000000000000000000000000000000000000000009b6e64a8ec60000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b303415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d9e19ad15da200000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b304415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000db44e049bb2c0000000000000000000000000000000000000000000000000000063eb89da4ed0000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 +- type: eip1559 + to: 0x162a433068f51e18b7d13932f27e66a3f99e6890 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '5' + max_priority_fee_per_gas: '2' + input: 0xa114b0ed000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000019a8241b305415641582f555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dca825c218b600000000000000000000000000000000000000000000000000000c7d713b49da0000000000000000000000000000a0ee7a142d267c1f36714e4a8f75612f20a797200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003 diff --git a/utils/examples/generated_rubicon.yaml b/utils/examples/generated_rubicon.yaml new file mode 100644 index 00000000..745d2248 --- /dev/null +++ b/utils/examples/generated_rubicon.yaml @@ -0,0 +1,155 @@ +transactions: +- type: eip1559 + to: 0x4b6ab5f819a515382b0deb6935d793817bb4af28 + value: '0.0' + gas_limit: 100000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0x095ea7b3000000000000000000000000d5ac451b0c50b9476107823af206ed814a2e2580ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +- type: eip1559 + to: 0x99b9b29b0b3e9542c6279615a960728380fd2ce4 + value: '0.0' + gas_limit: 100000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0x095ea7b3000000000000000000000000d5ac451b0c50b9476107823af206ed814a2e2580ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +- type: eip1559 + to: 0x4b6ab5f819a515382b0deb6935d793817bb4af28 + value: '0.01' + gas_limit: 100000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: '0xd0e30db0' +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000029a2241af62c000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0x4b6ab5f819a515382b0deb6935d793817bb4af28 + value: '1' + gas_limit: 100000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: '0xd0e30db0' +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af280000000000000000000000000000000000000000000000002b05699353b6000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000028f0815ec767000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000029a2241af62c000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af280000000000000000000000000000000000000000000000002a53c6d724f1000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af28000000000000000000000000000000000000000000000000283edea298a2000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af280000000000000000000000000000000000000000000000002bb70c4f827b000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af28000000000000000000000000000000000000000000000000278d3be669dd000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af280000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af28000000000000000000000000000000000000000000000000295b163616aa000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0x99b9b29b0b3e9542c6279615a960728380fd2ce4 + value: '0.0' + gas_limit: 200000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: '0xde5f72fd' +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000029a2241af62c000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f0140000000000000000000000000000000000000000000000002b05699353b6000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000028f0815ec767000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000029a2241af62c000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f0140000000000000000000000000000000000000000000000002a53c6d724f1000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f0140000000000000000000000000000000000000000000000002bb70c4f827b000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f0140000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 diff --git a/utils/examples/rubicon_dex_transactions.yaml b/utils/examples/rubicon_dex_transactions.yaml new file mode 100644 index 00000000..9b257a18 --- /dev/null +++ b/utils/examples/rubicon_dex_transactions.yaml @@ -0,0 +1,206 @@ +# RubiconMarket DEX Transaction Templates - WITH APPROVALS +# Uses offer(uint256,address,uint256,address,uint256,bool) - Selector: 0xe1a6f014 +# +# Contract Addresses: +# RubiconMarket: 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 +# WETH9: 0x5FbDB2315678afecb367f032d93F642f64180aa3 +# USDCWithFaucet: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 + +transactions: + # Approve RubiconMarket to spend unlimited WETH + - type: eip1559 + to: "0x5FbDB2315678afecb367f032d93F642f64180aa3" + value: "0.0" + gas_limit: 100000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0x095ea7b30000000000000000000000009fe46736679d2d9a65f0992f2272de9f3c7fa6e0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + # Approve RubiconMarket to spend unlimited USDC + - type: eip1559 + to: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" + value: "0.0" + gas_limit: 100000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0x095ea7b30000000000000000000000009fe46736679d2d9a65f0992f2272de9f3c7fa6e0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + # Deposit 0.001 ETH to get WETH + - type: eip1559 + to: "0x5FbDB2315678afecb367f032d93F642f64180aa3" + value: "0.001" + gas_limit: 100000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xd0e30db0" + + # SELL offer: 0.01 WETH for 30 USDC @ 3000 USDC/WETH + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000001a055690d9db80000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # Deposit 1 ETH to get WETH + - type: eip1559 + to: "0x5FbDB2315678afecb367f032d93F642f64180aa3" + value: "1" + gas_limit: 100000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xd0e30db0" + + # SELL offer: 0.01 WETH for 31 USDC @ 3100 USDC/WETH + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000001ab2b0f56c7700000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # SELL offer: 0.01 WETH for 29.5 USDC @ 2950 USDC/WETH + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa30000000000000000000000000000000000000000000000019969a3641f380000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # SELL offer: 0.01 WETH for 30 USDC @ 3000 USDC/WETH + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000001a055690d9db80000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # SELL offer: 0.01 WETH for 30.5 USDC @ 3050 USDC/WETH + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000001a784e33c54c80000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # SELL offer: 0.01 WETH for 29 USDC @ 2900 USDC/WETH + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa30000000000000000000000000000000000000000000000018fae27693b400000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # SELL offer: 0.01 WETH for 31.5 USDC @ 3150 USDC/WETH + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000001adb30a8b81100000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # SELL offer: 0.01 WETH for 28.5 USDC @ 2850 USDC/WETH + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa30000000000000000000000000000000000000000000000018c2da8f5c2c00000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # SELL offer: 0.01 WETH for 32 USDC @ 3200 USDC/WETH + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000001b1ae4d6e2ef50000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # SELL offer: 0.01 WETH for 29.8 USDC @ 2980 USDC/WETH + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa30000000000000000000000000000000000000000000000019d9c7f8d9da00000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f051200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # Mint 10,000 USDC using adminMint() + - type: eip1559 + to: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" + value: "0.0" + gas_limit: 200000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0x6d1b229d" + + # BUY offer: 30 USDC for 0.01 WETH @ 3000 USDC/WETH (WILL MATCH SELL) + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000001a055690d9db80000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # BUY offer: 31 USDC for 0.01 WETH @ 3100 USDC/WETH (WILL MATCH SELL) + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000001ab2b0f56c7700000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # BUY offer: 29.5 USDC for 0.01 WETH @ 2950 USDC/WETH (WILL MATCH SELL) + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f0140000000000000000000000000000000000000000000000019969a3641f380000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # BUY offer: 30 USDC for 0.01 WETH @ 3000 USDC/WETH (WILL MATCH SELL) + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000001a055690d9db80000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # BUY offer: 30.5 USDC for 0.01 WETH @ 3050 USDC/WETH (WILL MATCH SELL) + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000001a784e33c54c80000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # BUY offer: 31.5 USDC for 0.01 WETH @ 3150 USDC/WETH (WILL MATCH SELL) + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000001adb30a8b81100000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + + # BUY offer: 32 USDC for 0.01 WETH @ 3200 USDC/WETH (WILL MATCH SELL) + - type: eip1559 + to: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" + value: "0.0" + gas_limit: 500000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "0xe1a6f014000000000000000000000000000000000000000000000001b1ae4d6e2ef50000000000000000000000000000e7f1725e7734ce288f8367e1bb143e90bb3f0512000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" \ No newline at end of file diff --git a/utils/examples/simple_transactions.yaml b/utils/examples/simple_transactions.yaml new file mode 100644 index 00000000..29ac705b --- /dev/null +++ b/utils/examples/simple_transactions.yaml @@ -0,0 +1,40 @@ +# Simple Transaction Templates +# +# This file contains basic EIP-1559 transaction templates for general testing. +# Use this for simple value transfers and basic contract interactions. + +transactions: + # Simple ETH transfer + - type: eip1559 + to: "0x0000000000000000000000000000000000000005" + value: "0.001" + gas_limit: 21000 + max_fee_per_gas: "2" + max_priority_fee_per_gas: "1" + input: "" + + # Transfer with slightly higher value + - type: eip1559 + to: "0x0000000000000000000000000000000000000006" + value: "0.01" + gas_limit: 21000 + max_fee_per_gas: "3" + max_priority_fee_per_gas: "1.5" + input: "" + + # Contract interaction with calldata + - type: eip1559 + to: "0x0000000000000000000000000000000000000007" + value: "0.0" + gas_limit: 100000 + max_fee_per_gas: "5" + max_priority_fee_per_gas: "2" + input: "0x095ea7b3000000000000000000000000000000000000000000000000000000000000dead" + +# Usage Example: +# +# cargo run --bin malachitebft-eth-utils -- spam \ +# --config utils/examples/simple_transactions.yaml \ +# --rate 50 \ +# --num-txs 500 \ +# --rpc-url 127.0.0.1:8545 diff --git a/utils/scripts/analyze_gas.py b/utils/scripts/analyze_gas.py new file mode 100755 index 00000000..1322ea01 --- /dev/null +++ b/utils/scripts/analyze_gas.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +""" +Gas Analysis Script + +This script: +1. Reads dex_spammer log files +2. Extracts transaction hashes from log entries +3. Fetches transaction receipts via RPC +4. Saves all receipts to gas_analyze.json +""" + +import argparse +import json +import re +import sys +import requests +from typing import List, Dict, Any + + +def extract_tx_hashes(log_file_path: str) -> List[str]: + """ + Parse log file and extract all transaction hashes. + + Expected log format: + 2025-10-13T13:11:14.355726Z INFO malachitebft_eth_utils::spammer: Sent tx with hash. nonce=540895 tx_hash=0x... + """ + tx_hashes = [] + tx_hash_pattern = re.compile(r'tx_hash=(0x[a-fA-F0-9]{64})') + + try: + with open(log_file_path, 'r') as f: + for line in f: + match = tx_hash_pattern.search(line) + if match: + tx_hash = match.group(1) + tx_hashes.append(tx_hash) + + print(f"Extracted {len(tx_hashes)} transaction hashes from {log_file_path}") + return tx_hashes + + except FileNotFoundError: + print(f"Error: File '{log_file_path}' not found", file=sys.stderr) + sys.exit(1) + except Exception as e: + print(f"Error reading file: {e}", file=sys.stderr) + sys.exit(1) + + +def fetch_transaction_receipt(tx_hash: str, rpc_url: str) -> Dict[str, Any]: + """ + Fetch transaction receipt via eth_getTransactionReceipt RPC call. + """ + payload = { + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": [tx_hash], + "id": 1 + } + + headers = { + "Content-Type": "application/json" + } + + try: + response = requests.post(rpc_url, json=payload, headers=headers, timeout=10) + response.raise_for_status() + result = response.json() + + if "error" in result: + print(f"RPC error for {tx_hash}: {result['error']}", file=sys.stderr) + return None + + return result.get("result") + + except requests.exceptions.RequestException as e: + print(f"Request error for {tx_hash}: {e}", file=sys.stderr) + return None + + +def main(): + parser = argparse.ArgumentParser( + description="Analyze gas usage from dex_spammer logs" + ) + parser.add_argument( + "log_file", + help="Path to the dex_spammer log file" + ) + parser.add_argument( + "--rpc-url", + default="http://127.0.0.1:8545", + help="RPC endpoint URL (default: http://127.0.0.1:8545)" + ) + parser.add_argument( + "--output", + default="gas_analyze.json", + help="Output JSON file (default: gas_analyze.json)" + ) + + args = parser.parse_args() + + print(f"Starting gas analysis...") + print(f"Log file: {args.log_file}") + print(f"RPC URL: {args.rpc_url}") + print(f"Output file: {args.output}") + print() + + # Extract transaction hashes + tx_hashes = extract_tx_hashes(args.log_file) + + if not tx_hashes: + print("No transaction hashes found in log file") + sys.exit(0) + + # Fetch receipts + receipts = [] + successful = 0 + failed = 0 + + print(f"\nFetching transaction receipts...") + for i, tx_hash in enumerate(tx_hashes, 1): + print(f"[{i}/{len(tx_hashes)}] Fetching receipt for {tx_hash}...", end=" ") + + receipt = fetch_transaction_receipt(tx_hash, args.rpc_url) + + if receipt: + receipts.append({ + "tx_hash": tx_hash, + "receipt": receipt + }) + successful += 1 + print("✓") + else: + failed += 1 + print("✗") + + # Save to JSON file + print(f"\nSaving results to {args.output}...") + try: + with open(args.output, 'w') as f: + json.dump(receipts, f, indent=2) + print(f"Successfully saved {len(receipts)} receipts") + except Exception as e: + print(f"Error writing output file: {e}", file=sys.stderr) + sys.exit(1) + + # Calculate gas statistics + gas_used_values = [] + for item in receipts: + receipt = item.get("receipt") + if receipt and receipt.get("gasUsed"): + # Convert hex string to integer + gas_used_hex = receipt["gasUsed"] + if isinstance(gas_used_hex, str) and gas_used_hex.startswith("0x"): + gas_used = int(gas_used_hex, 16) + else: + gas_used = int(gas_used_hex) + gas_used_values.append(gas_used) + + # Summary + print("\n=== Summary ===") + print(f"Total transactions: {len(tx_hashes)}") + print(f"Successful: {successful}") + print(f"Failed: {failed}") + print(f"Output file: {args.output}") + + if gas_used_values: + avg_gas = sum(gas_used_values) / len(gas_used_values) + min_gas = min(gas_used_values) + max_gas = max(gas_used_values) + total_gas = sum(gas_used_values) + + print("\n=== Gas Usage Statistics ===") + print(f"Average gas used: {avg_gas:,.2f}") + print(f"Minimum gas used: {min_gas:,}") + print(f"Maximum gas used: {max_gas:,}") + print(f"Total gas used: {total_gas:,}") + else: + print("\nNo gas usage data available") + + +if __name__ == "__main__": + main() diff --git a/utils/src/dex_templates.rs b/utils/src/dex_templates.rs new file mode 100644 index 00000000..64287f01 --- /dev/null +++ b/utils/src/dex_templates.rs @@ -0,0 +1,301 @@ +use std::fs; +use std::path::Path; + +use alloy_primitives::{Address, Bytes, U256}; +use color_eyre::eyre::{eyre, Result}; +use serde::{Deserialize, Serialize}; + +/// Root structure for deserializing transaction templates from YAML +#[derive(Debug, Deserialize, Serialize)] +pub struct TransactionTemplates { + pub transactions: Vec, +} + +/// Enum representing different transaction types +#[derive(Debug, Deserialize, Serialize, Clone)] +#[serde(tag = "type", rename_all = "lowercase")] +pub enum TxTemplate { + Eip1559(Eip1559Template), + Eip4844(Eip4844Template), +} + +/// Template for EIP-1559 transactions +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct Eip1559Template { + /// Recipient address + pub to: String, + /// Value to send in ETH (as string, e.g., "0.001") + pub value: String, + /// Gas limit + pub gas_limit: u64, + /// Maximum fee per gas in gwei (as string, e.g., "2") + pub max_fee_per_gas: String, + /// Maximum priority fee per gas in gwei (as string, e.g., "1") + pub max_priority_fee_per_gas: String, + /// Optional hex-encoded input data (e.g., "0xabcd1234") + #[serde(default)] + pub input: String, +} + +/// Template for EIP-4844 (blob) transactions +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct Eip4844Template { + /// Recipient address + pub to: String, + /// Value to send in ETH (as string, e.g., "0.001") + pub value: String, + /// Gas limit + pub gas_limit: u64, + /// Maximum fee per gas in gwei (as string, e.g., "50") + pub max_fee_per_gas: String, + /// Maximum priority fee per gas in gwei (as string, e.g., "1000") + pub max_priority_fee_per_gas: String, + /// Maximum fee per blob gas in gwei (as string, e.g., "1") + pub max_fee_per_blob_gas: String, +} + +/// Parse ETH value from string (e.g., "0.001" -> Wei) +pub fn parse_eth_value(eth: &str) -> Result { + let value: f64 = eth + .parse() + .map_err(|e| eyre!("Failed to parse ETH value '{}': {}", eth, e))?; + + if value < 0.0 { + return Err(eyre!("ETH value cannot be negative: {}", eth)); + } + + // Convert ETH to Wei (1 ETH = 10^18 Wei) + let wei = (value * 1e18) as u128; + Ok(U256::from(wei)) +} + +/// Parse gwei value from string (e.g., "2" -> Wei) +pub fn parse_gwei_value(gwei: &str) -> Result { + let value: f64 = gwei + .parse() + .map_err(|e| eyre!("Failed to parse gwei value '{}': {}", gwei, e))?; + + if value < 0.0 { + return Err(eyre!("Gwei value cannot be negative: {}", gwei)); + } + + // Convert gwei to Wei (1 gwei = 10^9 Wei) + Ok((value * 1e9) as u128) +} + +/// Parse hex-encoded address from string +pub fn parse_address(addr: &str) -> Result
{ + addr.parse::
() + .map_err(|e| eyre!("Failed to parse address '{}': {}", addr, e)) +} + +/// Parse hex-encoded input data from string +pub fn parse_input_data(input: &str) -> Result { + if input.is_empty() { + return Ok(Bytes::default()); + } + + let hex_str = input.trim_start_matches("0x"); + let bytes = + hex::decode(hex_str).map_err(|e| eyre!("Failed to parse input data '{}': {}", input, e))?; + + Ok(Bytes::from(bytes)) +} + +/// Load transaction templates from a YAML file +pub fn load_templates(path: impl AsRef) -> Result> { + let path_ref = path.as_ref(); + let content = fs::read_to_string(path_ref).map_err(|e| { + eyre!( + "Failed to read template file '{}': {}", + path_ref.display(), + e + ) + })?; + + let templates: TransactionTemplates = serde_yaml::from_str(&content) + .map_err(|e| eyre!("Failed to parse YAML from '{}': {}", path_ref.display(), e))?; + + if templates.transactions.is_empty() { + return Err(eyre!( + "Template file '{}' contains no transactions", + path_ref.display() + )); + } + + Ok(templates.transactions) +} + +/// Save transaction templates to a YAML file +pub fn save_templates(templates: &[TxTemplate], path: impl AsRef) -> Result<()> { + let path_ref = path.as_ref(); + + // Create parent directory if it doesn't exist + if let Some(parent) = path_ref.parent() { + fs::create_dir_all(parent)?; + } + + let wrapper = TransactionTemplates { + transactions: templates.to_vec(), + }; + + let yaml_content = serde_yaml::to_string(&wrapper) + .map_err(|e| eyre!("Failed to serialize templates to YAML: {}", e))?; + + fs::write(path_ref, yaml_content).map_err(|e| { + eyre!( + "Failed to write template file '{}': {}", + path_ref.display(), + e + ) + })?; + + Ok(()) +} + +/// Round-robin selector for cycling through transaction templates +pub struct RoundRobinSelector { + templates: Vec, + current_index: usize, +} + +impl RoundRobinSelector { + /// Create a new round-robin selector with the given templates + pub fn new(templates: Vec) -> Self { + Self { + templates, + current_index: 0, + } + } + + /// Get the next template in round-robin fashion + pub fn next_template(&mut self) -> &TxTemplate { + let template = &self.templates[self.current_index]; + self.current_index = (self.current_index + 1) % self.templates.len(); + template + } + + /// Reset the selector back to the first template + /// Used when nonce mismatches occur to restart the template sequence + pub fn reset(&mut self) { + self.current_index = 0; + } + + /// Set the selector to a specific template index + /// Used for smart nonce recovery to resume at the correct position in the template cycle + pub fn set_index(&mut self, index: usize) { + self.current_index = index % self.templates.len(); + } + + /// Get the number of templates in the cycle + pub fn template_count(&self) -> usize { + self.templates.len() + } + + /// Get the current template index + pub fn current_index(&self) -> usize { + self.current_index + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_eth_value() { + assert_eq!( + parse_eth_value("1").unwrap(), + U256::from(1_000_000_000_000_000_000u128) + ); + assert_eq!( + parse_eth_value("0.001").unwrap(), + U256::from(1_000_000_000_000_000u128) + ); + assert_eq!(parse_eth_value("0").unwrap(), U256::ZERO); + } + + #[test] + fn test_parse_eth_value_invalid() { + assert!(parse_eth_value("invalid").is_err()); + assert!(parse_eth_value("-1").is_err()); + } + + #[test] + fn test_parse_gwei_value() { + assert_eq!(parse_gwei_value("1").unwrap(), 1_000_000_000u128); + assert_eq!(parse_gwei_value("2.5").unwrap(), 2_500_000_000u128); + assert_eq!(parse_gwei_value("0").unwrap(), 0u128); + } + + #[test] + fn test_parse_gwei_value_invalid() { + assert!(parse_gwei_value("invalid").is_err()); + assert!(parse_gwei_value("-1").is_err()); + } + + #[test] + fn test_parse_address() { + let addr = "0x0000000000000000000000000000000000000005"; + assert!(parse_address(addr).is_ok()); + } + + #[test] + fn test_parse_address_invalid() { + assert!(parse_address("invalid").is_err()); + assert!(parse_address("0x123").is_err()); // Too short + } + + #[test] + fn test_parse_input_data() { + assert_eq!(parse_input_data("").unwrap(), Bytes::default()); + assert_eq!(parse_input_data("0x").unwrap(), Bytes::default()); + + let data = parse_input_data("0xabcd").unwrap(); + assert_eq!(data.len(), 2); + } + + #[test] + fn test_parse_input_data_invalid() { + assert!(parse_input_data("0xGGGG").is_err()); // Invalid hex + } + + #[test] + fn test_round_robin_selector() { + let templates = vec![ + TxTemplate::Eip1559(Eip1559Template { + to: "0x0000000000000000000000000000000000000001".to_string(), + value: "0.001".to_string(), + gas_limit: 21000, + max_fee_per_gas: "2".to_string(), + max_priority_fee_per_gas: "1".to_string(), + input: "".to_string(), + }), + TxTemplate::Eip1559(Eip1559Template { + to: "0x0000000000000000000000000000000000000002".to_string(), + value: "0.002".to_string(), + gas_limit: 21000, + max_fee_per_gas: "3".to_string(), + max_priority_fee_per_gas: "1.5".to_string(), + input: "".to_string(), + }), + ]; + + let mut selector = RoundRobinSelector::new(templates); + + // First iteration + if let TxTemplate::Eip1559(t) = selector.next_template() { + assert_eq!(t.to, "0x0000000000000000000000000000000000000001"); + } + + // Second iteration + if let TxTemplate::Eip1559(t) = selector.next_template() { + assert_eq!(t.to, "0x0000000000000000000000000000000000000002"); + } + + // Should wrap around + if let TxTemplate::Eip1559(t) = selector.next_template() { + assert_eq!(t.to, "0x0000000000000000000000000000000000000001"); + } + } +} diff --git a/utils/src/dexalot_generator.rs b/utils/src/dexalot_generator.rs new file mode 100644 index 00000000..9f380f47 --- /dev/null +++ b/utils/src/dexalot_generator.rs @@ -0,0 +1,180 @@ +use alloy_dyn_abi::{DynSolValue, JsonAbiExt, Word}; +use alloy_json_abi::Function; +use alloy_primitives::{Address, U256}; +use color_eyre::eyre::Result; + +use crate::dex_templates::{Eip1559Template, TxTemplate}; + +/// Dexalot contract addresses +pub struct DexalotConfig { + pub portfolio: Address, + pub tradepairs: Address, +} + +/// Generate Dexalot trading transactions dynamically for a given trader address +pub fn generate_dexalot_transactions( + trader: Address, + config: DexalotConfig, +) -> Result> { + let mut transactions = Vec::new(); + + // 1. Deposit transaction + let deposit_calldata = encode_deposit_native(trader)?; + transactions.push(TxTemplate::Eip1559(Eip1559Template { + to: format!("{:#x}", config.portfolio), + value: "11".to_string(), + gas_limit: 200000, + max_fee_per_gas: "5".to_string(), + max_priority_fee_per_gas: "2".to_string(), + input: format!("0x{}", hex::encode(deposit_calldata)), + })); + + // Trading pair configuration + let tradepair_id = + hex::decode("415641582f555344540000000000000000000000000000000000000000000000")?; + let base_price = 15.0; // 15 USDT + let price_increment = 0.1; + + // Varying sell quantities to create partial fills + let sell_quantities = vec![ + U256::from(1_000_000_000_000_000_000u128), // 1.0 AVAX + U256::from(1_500_000_000_000_000_000u128), // 1.5 AVAX + U256::from(800_000_000_000_000_000u128), // 0.8 AVAX + U256::from(1_200_000_000_000_000_000u128), // 1.2 AVAX + U256::from(900_000_000_000_000_000u128), // 0.9 AVAX + U256::from(1_100_000_000_000_000_000u128), // 1.1 AVAX + U256::from(700_000_000_000_000_000u128), // 0.7 AVAX + U256::from(1_300_000_000_000_000_000u128), // 1.3 AVAX + U256::from(950_000_000_000_000_000u128), // 0.95 AVAX + U256::from(1_050_000_000_000_000_000u128), // 1.05 AVAX + ]; + + // Varying buy quantities to create partial fills + let buy_quantities = vec![ + U256::from(600_000_000_000_000_000u128), // 0.6 AVAX + U256::from(750_000_000_000_000_000u128), // 0.75 AVAX + U256::from(500_000_000_000_000_000u128), // 0.5 AVAX + U256::from(850_000_000_000_000_000u128), // 0.85 AVAX + U256::from(650_000_000_000_000_000u128), // 0.65 AVAX + U256::from(550_000_000_000_000_000u128), // 0.55 AVAX + U256::from(700_000_000_000_000_000u128), // 0.7 AVAX + U256::from(800_000_000_000_000_000u128), // 0.8 AVAX + U256::from(450_000_000_000_000_000u128), // 0.45 AVAX + U256::from(900_000_000_000_000_000u128), // 0.9 AVAX + ]; + + // 2-11. Generate 10 SELL orders + for i in 0..10 { + let client_id = generate_client_order_id(i); + let price = base_price - 0.5 + (i as f64) * price_increment; + let price_wei = U256::from((price * 1e18) as u128); + + let order_calldata = encode_add_order_list( + &client_id, + &tradepair_id, + price_wei, + sell_quantities[i as usize], + trader, + 1, + )?; + + transactions.push(TxTemplate::Eip1559(Eip1559Template { + to: format!("{:#x}", config.tradepairs), + value: "0.0".to_string(), + gas_limit: 1500000, + max_fee_per_gas: "5".to_string(), + max_priority_fee_per_gas: "2".to_string(), + input: format!("0x{}", hex::encode(order_calldata)), + })); + } + + // 12-21. Generate 10 BUY orders + for i in 0..10 { + let client_id = generate_client_order_id(100 + i); + let price = base_price + (i as f64) * price_increment; + let price_wei = U256::from((price * 1e18) as u128); + + let order_calldata = encode_add_order_list( + &client_id, + &tradepair_id, + price_wei, + buy_quantities[i as usize], + trader, + 0, + )?; + + transactions.push(TxTemplate::Eip1559(Eip1559Template { + to: format!("{:#x}", config.tradepairs), + value: "0.0".to_string(), + gas_limit: 1500000, + max_fee_per_gas: "5".to_string(), + max_priority_fee_per_gas: "2".to_string(), + input: format!("0x{}", hex::encode(order_calldata)), + })); + } + + Ok(transactions) +} + +/// Encode depositNative(address,uint8) function call +fn encode_deposit_native(trader: Address) -> Result> { + let function = Function::parse("depositNative(address,uint8)")?; + let args = vec![ + DynSolValue::Address(trader), + DynSolValue::Uint(U256::from(0), 8), + ]; + Ok(function.abi_encode_input(&args)?) +} + +/// Encode addOrderList function call +fn encode_add_order_list( + client_order_id: &[u8], + tradepair_id: &[u8], + price: U256, + quantity: U256, + trader: Address, + side: u8, // 0 = BUY, 1 = SELL +) -> Result> { + let function = Function::parse( + "addOrderList((bytes32,bytes32,uint256,uint256,address,uint8,uint8,uint8,uint8)[])", + )?; + + // Build the order tuple + let client_order_id_word = Word::try_from(client_order_id) + .map_err(|_| color_eyre::eyre::eyre!("Invalid client order ID length"))?; + let tradepair_id_word = Word::try_from(tradepair_id) + .map_err(|_| color_eyre::eyre::eyre!("Invalid tradepair ID length"))?; + + let order_tuple = DynSolValue::Tuple(vec![ + DynSolValue::FixedBytes(Word::from(client_order_id_word), 32), + DynSolValue::FixedBytes(Word::from(tradepair_id_word), 32), + DynSolValue::Uint(price, 256), + DynSolValue::Uint(quantity, 256), + DynSolValue::Address(trader), + DynSolValue::Uint(U256::from(side), 8), // side + DynSolValue::Uint(U256::from(1), 8), // type1 = LIMIT + DynSolValue::Uint(U256::from(0), 8), // type2 = GTC + DynSolValue::Uint(U256::from(3), 8), // stp = NONE + ]); + + let orders_array = DynSolValue::Array(vec![order_tuple]); + let args = vec![orders_array]; + + Ok(function.abi_encode_input(&args)?) +} + +/// Generate unique client order ID using timestamp +fn generate_client_order_id(num: u32) -> Vec { + use std::time::{SystemTime, UNIX_EPOCH}; + + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + let unique_id = (timestamp * 1000) + num as u64; + + let mut bytes = vec![0u8; 32]; + let id_bytes = unique_id.to_be_bytes(); + bytes[24..32].copy_from_slice(&id_bytes); + bytes +} diff --git a/utils/src/lib.rs b/utils/src/lib.rs index 4de938f5..c2ee58f9 100644 --- a/utils/src/lib.rs +++ b/utils/src/lib.rs @@ -2,12 +2,17 @@ use alloy_primitives::Address; use clap::{Parser, Subcommand, ValueHint}; use color_eyre::eyre::Result; use genesis::{generate_genesis, make_signers}; +use mempool_monitor::MempoolMonitor; use reqwest::Url; use spammer::Spammer; +pub mod dex_templates; +pub mod dexalot_generator; pub mod genesis; +pub mod mempool_monitor; pub mod modify_config; pub mod poa; +pub mod rubicon_generator; pub mod spammer; pub mod tx; pub mod validator_manager; @@ -16,7 +21,7 @@ pub mod validator_manager; #[command(author, version, about, long_about = None)] pub struct Cli { #[command(subcommand)] - command: Commands, + pub command: Commands, } impl Cli { @@ -42,6 +47,7 @@ impl Cli { Commands::Spam(spam_cmd) => spam_cmd.run().await, Commands::Poa(poa_cmd) => poa_cmd.run().await, Commands::SpamContract(spam_contract_cmd) => spam_contract_cmd.run().await, + Commands::MonitorMempool(monitor_cmd) => monitor_cmd.run().await, Commands::ModifyConfig(modify_config_cmd) => modify_config_cmd.run(), } } @@ -120,6 +126,10 @@ pub enum Commands { #[command(arg_required_else_help = true)] SpamContract(SpamContractCmd), + /// Monitor mempool and log when it becomes empty + #[command(arg_required_else_help = true)] + MonitorMempool(MonitorMempoolCmd), + /// Apply custom node configurations from a TOML file #[command(arg_required_else_help = true)] ModifyConfig(ModifyConfigCmd), @@ -130,6 +140,12 @@ pub struct SpamCmd { /// URL of the execution client's RPC endpoint (e.g., http://127.0.0.1:8545, https://eth.example.com) #[clap(long, default_value = "http://127.0.0.1:8545")] rpc_url: String, + /// Enable DEX transaction spamming mode (loads exchange_transactions.yaml) + #[clap(long, default_value = "false")] + pub dex: bool, + /// Path to custom transaction template YAML file (used with --dex) + #[clap(long)] + template: Option, /// Number of transactions to send #[clap(short, long, default_value = "0")] num_txs: u64, @@ -149,24 +165,175 @@ pub struct SpamCmd { #[clap(long, default_value = "0")] signer_index: usize, + /// Dexalot Portfolio contract address (required for dexalot templates) + #[clap(long, required_if_eq("template", "dexalot"))] + portfolio: Option
, + + /// Dexalot TradePairs contract address (required for dexalot templates) + #[clap(long, required_if_eq("template", "dexalot"))] + tradepairs: Option
, + + /// RubiconMarket contract address (for rubicon templates) + #[clap(long)] + rubicon_market: Option
, + + /// WETH9 token contract address (for rubicon templates) + #[clap(long)] + weth: Option
, + + /// USDC token contract address (for rubicon templates) + #[clap(long)] + usdc: Option
, + #[clap(long, short)] chain_id: u64, } +#[derive(Parser, Debug, Clone, PartialEq)] +pub struct MonitorMempoolCmd { + /// URL of the execution client's RPC endpoint + #[clap(long, default_value = "127.0.0.1:8545")] + rpc_url: String, + + /// Polling interval in milliseconds (lower = more precise, higher CPU usage) + #[clap(long, default_value = "10")] + poll_interval_ms: u64, +} + +impl MonitorMempoolCmd { + pub(crate) async fn run(&self) -> Result<()> { + let Self { + rpc_url, + poll_interval_ms, + } = self; + + let url = if rpc_url.starts_with("http://") || rpc_url.starts_with("https://") { + rpc_url.parse()? + } else { + format!("http://{rpc_url}").parse()? + }; + MempoolMonitor::new(url, *poll_interval_ms).run().await + } +} impl SpamCmd { pub(crate) async fn run(&self) -> Result<()> { let Self { rpc_url, + dex, + template, num_txs, rate, interval, time, blobs, signer_index, + portfolio, + tradepairs, + rubicon_market, + weth, + usdc, chain_id, } = self; - let url: Url = rpc_url.parse()?; + let url: Url = if rpc_url.starts_with("http://") || rpc_url.starts_with("https://") { + rpc_url.parse()? + } else { + format!("http://{rpc_url}").parse()? + }; + + // Load DEX templates if --dex flag is set + let templates = if *dex { + // Use custom template path if provided, otherwise use default + let config_path = template + .as_deref() + .unwrap_or("utils/examples/exchange_transactions.yaml"); + + // Check if this is a dexalot template (generate dynamically) + if config_path.contains("dexalot") { + // Get signer address for dynamic template generation + let signers = make_signers(); + let signer_address = signers[*signer_index].address(); + + // Require both portfolio and tradepairs addresses + let portfolio_addr = portfolio.ok_or_else(|| { + color_eyre::eyre::eyre!( + "Dexalot template requires --portfolio address to be specified" + ) + })?; + let tradepairs_addr = tradepairs.ok_or_else(|| { + color_eyre::eyre::eyre!( + "Dexalot template requires --tradepairs address to be specified" + ) + })?; + + let config = dexalot_generator::DexalotConfig { + portfolio: portfolio_addr, + tradepairs: tradepairs_addr, + }; + + let templates = + dexalot_generator::generate_dexalot_transactions(signer_address, config)?; + + // Save generated templates to file + let output_path = "utils/examples/generated_dexalot.yaml"; + if let Err(e) = dex_templates::save_templates(&templates, output_path) { + eprintln!("Warning: Failed to save generated template: {e}"); + } else { + println!("Generated Dexalot template saved to: {output_path}"); + } + + Some(templates) + } else if config_path.contains("rubicon") || rubicon_market.is_some() { + // Check if this is a rubicon template (generate dynamically) + // Require all three contract addresses + let rubicon_market_addr = rubicon_market.ok_or_else(|| { + color_eyre::eyre::eyre!( + "Rubicon template requires --rubicon-market address to be specified" + ) + })?; + let weth_addr = weth.ok_or_else(|| { + color_eyre::eyre::eyre!( + "Rubicon template requires --weth address to be specified" + ) + })?; + let usdc_addr = usdc.ok_or_else(|| { + color_eyre::eyre::eyre!( + "Rubicon template requires --usdc address to be specified" + ) + })?; + + let config = rubicon_generator::RubiconConfig { + rubicon_market: rubicon_market_addr, + weth: weth_addr, + usdc: usdc_addr, + }; + + println!("Generating Rubicon DEX transaction templates with custom addresses"); + let templates = rubicon_generator::generate_rubicon_transactions(config)?; + + // Save generated templates to file + let output_path = "utils/examples/generated_rubicon.yaml"; + if let Err(e) = dex_templates::save_templates(&templates, output_path) { + eprintln!("Warning: Failed to save generated template: {e}"); + } else { + println!("Generated Rubicon template saved to: {output_path}"); + } + + Some(templates) + } else { + println!("Loading DEX transaction templates from: {config_path}"); + Some(dex_templates::load_templates(config_path)?) + } + } else if template.is_some() { + // If template is specified but --dex is not set, warn the user + eprintln!( + "Warning: --template specified without --dex flag. Template will be ignored." + ); + None + } else { + None + }; + let config = spammer::SpammerConfig { max_num_txs: *num_txs, max_time: *time, @@ -175,7 +342,8 @@ impl SpamCmd { blobs: *blobs, chain_id: *chain_id, }; - Spammer::new(url, *signer_index, config)?.run().await + + Spammer::new(url, *signer_index, config, templates)?.run().await } } diff --git a/utils/src/main.rs b/utils/src/main.rs index 2bb31f2b..33faef04 100644 --- a/utils/src/main.rs +++ b/utils/src/main.rs @@ -1,11 +1,62 @@ +use std::fs::{self, File}; + +use chrono::Local; use clap::Parser; use color_eyre::eyre::Result; -use emerald_utils::Cli; +use emerald_utils::{Cli, Commands}; +use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::util::SubscriberInitExt; +use tracing_subscriber::{fmt, EnvFilter}; #[tokio::main] async fn main() -> Result<()> { color_eyre::install()?; - tracing_subscriber::fmt::init(); - Cli::parse().run().await + let cli = Cli::parse(); + + // Initialize tracing based on command type + match &cli.command { + Commands::Spam(spam_cmd) if spam_cmd.dex => { + // Create logs directory + let log_dir = "./utils/logs"; + fs::create_dir_all(log_dir)?; + + // Create log file with timestamp + let timestamp = Local::now().format("%Y%m%d_%H%M%S"); + let log_file_path = format!("{log_dir}/dex_spammer_{timestamp}.log"); + let log_file = File::create(&log_file_path)?; + + println!("Logging to: {log_file_path}"); + + // Initialize file-based logger + tracing_subscriber::registry() + .with(EnvFilter::from_default_env().add_directive(tracing::Level::DEBUG.into())) + .with(fmt::layer().with_writer(log_file).with_ansi(false)) + .init(); + } + Commands::MonitorMempool(_) => { + // Create logs directory + let log_dir = "./utils/logs"; + fs::create_dir_all(log_dir)?; + + // Create log file with timestamp + let timestamp = Local::now().format("%Y%m%d_%H%M%S"); + let log_file_path = format!("{log_dir}/mempool_monitor_{timestamp}.log"); + let log_file = File::create(&log_file_path)?; + + println!("Logging to: {log_file_path}"); + + // Initialize file-based logger + tracing_subscriber::registry() + .with(EnvFilter::from_default_env().add_directive(tracing::Level::DEBUG.into())) + .with(fmt::layer().with_writer(log_file).with_ansi(false)) + .init(); + } + _ => { + // Default console logger for other commands + tracing_subscriber::fmt::init(); + } + } + + cli.run().await } diff --git a/utils/src/mempool_monitor.rs b/utils/src/mempool_monitor.rs new file mode 100644 index 00000000..1a54d56c --- /dev/null +++ b/utils/src/mempool_monitor.rs @@ -0,0 +1,214 @@ +use core::time::Duration; +use std::time::{SystemTime, UNIX_EPOCH}; + +use alloy_rpc_types_txpool::TxpoolStatus; +use color_eyre::eyre::Result; +use reqwest::{Client, Url}; +use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use tokio::signal; +use tokio::time::{interval, sleep}; +use tracing::{error, info, warn}; + +/// A monitor that tracks when the mempool becomes empty with precise timestamps. +/// +/// This monitor polls txpool_status at high frequency (configurable) and logs +/// the exact timestamp (in milliseconds) and mempool status using structured logging +pub struct MempoolMonitor { + client: RpcClient, + poll_interval_ms: u64, +} + +impl MempoolMonitor { + pub fn new(url: Url, poll_interval_ms: u64) -> Self { + Self { + client: RpcClient::new(url), + poll_interval_ms, + } + } + + /// Run the monitor indefinitely, logging mempool events using structured logging. + pub async fn run(self) -> Result<()> { + // Set up signal handler in a separate task + let (shutdown_tx, mut shutdown_rx) = tokio::sync::mpsc::channel::<()>(1); + + tokio::spawn(async move { + match signal::ctrl_c().await { + Ok(()) => { + eprintln!("\nReceived Ctrl+C signal"); + let _ = shutdown_tx.send(()).await; + } + Err(e) => { + eprintln!("Error setting up signal handler: {e}"); + } + } + }); + + let mut interval = interval(Duration::from_millis(self.poll_interval_ms)); + let mut last_was_empty: Option = None; + + println!("Starting mempool monitor. Press Ctrl+C to stop."); + info!( + "Starting mempool monitor with poll interval of {}ms", + self.poll_interval_ms + ); + + let mut start_timestamp: u64 = 0; + let mut end_timestamp: u64 = 0; + + loop { + tokio::select! { + _ = shutdown_rx.recv() => { + eprintln!("Shutting down monitor..."); + info!("Received shutdown signal, stopping monitor..."); + + // Print statistics + if start_timestamp > 0 && end_timestamp > 0 { + let duration_ms = end_timestamp - start_timestamp; + eprintln!("\n=== Mempool Monitor Statistics ==="); + eprintln!("Mempool was full for: {duration_ms} ms"); + eprintln!("Start timestamp: {start_timestamp}"); + eprintln!("End timestamp: {end_timestamp}"); + info!( + duration_ms = duration_ms, + start_timestamp = start_timestamp, + end_timestamp = end_timestamp, + "Mempool full duration statistics" + ); + } else { + warn!("No mempool full period detected during monitoring"); + eprintln!("\n=== Mempool Monitor Statistics ==="); + eprintln!("Mempool was never full during monitoring period"); + } + + break; + } + _ = interval.tick() => { + let timestamp_ms = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() as u64; + + match self + .client + .rpc_request::("txpool_status", json!([])) + .await + { + Ok(status) => { + let is_empty = status.pending == 0 && status.queued == 0; + + // Only log on state transitions or first poll + let should_log = match last_was_empty { + None => true, // First poll, log initial state + Some(was_empty) => was_empty != is_empty, // Log on transition + }; + + if is_empty && should_log { + // Mempool just became empty - record end_timestamp + if start_timestamp > 0 && end_timestamp == 0 { + end_timestamp = timestamp_ms; + eprintln!("Mempool not empty at timestamp: {end_timestamp}"); + + } + info!( + timestamp_ms = timestamp_ms, + event = "MEMPOOL_EMPTY", + pending = status.pending, + queued = status.queued, + "Mempool is now empty" + ); + + } else if !is_empty { + // Mempool just became filled - record start_timestamp + if start_timestamp == 0 { + start_timestamp = timestamp_ms; + eprintln!("Mempool empty at start timestamp: {start_timestamp}"); + } + info!( + timestamp_ms = timestamp_ms, + event = "MEMPOOL_FILLED", + pending = status.pending, + queued = status.queued, + "Mempool has transactions" + ); + } + + last_was_empty = Some(is_empty); + } + Err(e) => { + error!( + timestamp_ms = timestamp_ms, + error = %e, + "Error querying txpool_status" + ); + // Small backoff on error + sleep(Duration::from_millis(5)).await; + } + } + } + } + } + + Ok(()) + } +} + +struct RpcClient { + client: Client, + url: Url, +} + +impl RpcClient { + pub fn new(url: Url) -> Self { + let client = Client::new(); + Self { client, url } + } + + pub async fn rpc_request( + &self, + method: &str, + params: serde_json::Value, + ) -> Result { + let body = json!({ + "jsonrpc": "2.0", + "method": method, + "params": params, + "id": 1 + }); + let request = self + .client + .post(self.url.clone()) + .timeout(Duration::from_millis(100)) // Fast timeout for high-frequency polling + .header("Content-Type", "application/json") + .json(&body); + let body: JsonResponseBody = request.send().await?.error_for_status()?.json().await?; + + if let Some(error) = body.error { + Err(color_eyre::eyre::eyre!( + "Server Error {}: {}", + error.code, + error.message + )) + } else { + serde_json::from_value(body.result).map_err(Into::into) + } + } +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct JsonResponseBody { + pub jsonrpc: String, + #[serde(default)] + pub error: Option, + #[serde(default)] + pub result: serde_json::Value, + pub id: serde_json::Value, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +struct JsonError { + pub code: i64, + pub message: String, +} diff --git a/utils/src/rubicon_generator.rs b/utils/src/rubicon_generator.rs new file mode 100644 index 00000000..c81f951e --- /dev/null +++ b/utils/src/rubicon_generator.rs @@ -0,0 +1,161 @@ +use alloy_dyn_abi::{DynSolValue, JsonAbiExt}; +use alloy_json_abi::Function; +use alloy_primitives::{Address, U256}; +use color_eyre::eyre::Result; + +use crate::dex_templates::{Eip1559Template, TxTemplate}; + +/// Rubicon contract addresses +pub struct RubiconConfig { + pub rubicon_market: Address, + pub weth: Address, + pub usdc: Address, +} + +/// Generate Rubicon trading transactions dynamically +pub fn generate_rubicon_transactions(config: RubiconConfig) -> Result> { + let mut transactions = Vec::new(); + + // 1. Approve RubiconMarket to spend unlimited WETH + let weth_approve_calldata = encode_approve(config.rubicon_market, U256::MAX)?; + transactions.push(TxTemplate::Eip1559(Eip1559Template { + to: format!("{:#x}", config.weth), + value: "0.0".to_string(), + gas_limit: 100000, + max_fee_per_gas: "2".to_string(), + max_priority_fee_per_gas: "1".to_string(), + input: format!("0x{}", hex::encode(weth_approve_calldata)), + })); + + // 2. Approve RubiconMarket to spend unlimited USDC + let usdc_approve_calldata = encode_approve(config.rubicon_market, U256::MAX)?; + transactions.push(TxTemplate::Eip1559(Eip1559Template { + to: format!("{:#x}", config.usdc), + value: "0.0".to_string(), + gas_limit: 100000, + max_fee_per_gas: "2".to_string(), + max_priority_fee_per_gas: "1".to_string(), + input: format!("0x{}", hex::encode(usdc_approve_calldata)), + })); + + // 3. Deposit 0.01 ETH to get WETH for all 10 sell offers + let deposit_calldata = encode_deposit()?; + transactions.push(TxTemplate::Eip1559(Eip1559Template { + to: format!("{:#x}", config.weth), + value: "0.01".to_string(), + gas_limit: 100000, + max_fee_per_gas: "2".to_string(), + max_priority_fee_per_gas: "1".to_string(), + input: format!("0x{}", hex::encode(deposit_calldata)), + })); + + // 4-13. SELL offers at varying prices (2850-3200 USDC/WETH) + let sell_prices = [3000, 3100, 2950, 3000, 3050, 2900, 3150, 2850, 3200, 2980]; + let weth_amount = U256::from(1_000_000_000_000_000u128); // 0.001 WETH (10x smaller) + + // 4. First SELL offer + let usdc_amount = weth_amount * U256::from(sell_prices[0]); + let offer_calldata = encode_offer(weth_amount, config.weth, usdc_amount, config.usdc, 0, true)?; + transactions.push(TxTemplate::Eip1559(Eip1559Template { + to: format!("{:#x}", config.rubicon_market), + value: "0.0".to_string(), + gas_limit: 1500000, + max_fee_per_gas: "2".to_string(), + max_priority_fee_per_gas: "1".to_string(), + input: format!("0x{}", hex::encode(offer_calldata)), + })); + + // 5. Deposit 1 ETH to get WETH for remaining sells + let deposit_calldata_2 = encode_deposit()?; + transactions.push(TxTemplate::Eip1559(Eip1559Template { + to: format!("{:#x}", config.weth), + value: "1".to_string(), + gas_limit: 100000, + max_fee_per_gas: "2".to_string(), + max_priority_fee_per_gas: "1".to_string(), + input: format!("0x{}", hex::encode(deposit_calldata_2)), + })); + + // 6-13. Remaining 9 SELL offers + for price in &sell_prices[1..] { + let usdc_amount = weth_amount * U256::from(*price); + let offer_calldata = + encode_offer(weth_amount, config.weth, usdc_amount, config.usdc, 0, true)?; + + transactions.push(TxTemplate::Eip1559(Eip1559Template { + to: format!("{:#x}", config.rubicon_market), + value: "0.0".to_string(), + gas_limit: 1500000, + max_fee_per_gas: "2".to_string(), + max_priority_fee_per_gas: "1".to_string(), + input: format!("0x{}", hex::encode(offer_calldata)), + })); + } + + // 14. Mint 10,000 USDC using faucet() - USDCWithFaucet function + transactions.push(TxTemplate::Eip1559(Eip1559Template { + to: format!("{:#x}", config.usdc), + value: "0.0".to_string(), + gas_limit: 200000, + max_fee_per_gas: "2".to_string(), + max_priority_fee_per_gas: "1".to_string(), + input: "0xde5f72fd".to_string(), + })); + + // 15-21. BUY offers at varying prices (7 orders to match sells) + let buy_prices = [3000, 3100, 2950, 3000, 3050, 3150, 3200]; + + for price in buy_prices { + let usdc_amount = weth_amount * U256::from(price); + let offer_calldata = + encode_offer(usdc_amount, config.usdc, weth_amount, config.weth, 0, true)?; + + transactions.push(TxTemplate::Eip1559(Eip1559Template { + to: format!("{:#x}", config.rubicon_market), + value: "0.0".to_string(), + gas_limit: 1500000, + max_fee_per_gas: "2".to_string(), + max_priority_fee_per_gas: "1".to_string(), + input: format!("0x{}", hex::encode(offer_calldata)), + })); + } + + Ok(transactions) +} + +/// Encode approve(address,uint256) function call +fn encode_approve(spender: Address, amount: U256) -> Result> { + let function = Function::parse("approve(address,uint256)")?; + let args = vec![ + DynSolValue::Address(spender), + DynSolValue::Uint(amount, 256), + ]; + Ok(function.abi_encode_input(&args)?) +} + +/// Encode deposit() function call +fn encode_deposit() -> Result> { + let function = Function::parse("deposit()")?; + Ok(function.abi_encode_input(&[])?) +} + +/// Encode offer(uint256,address,uint256,address,uint256,bool) function call +fn encode_offer( + pay_amt: U256, + pay_gem: Address, + buy_amt: U256, + buy_gem: Address, + pos: u64, + matching_enabled: bool, +) -> Result> { + let function = Function::parse("offer(uint256,address,uint256,address,uint256,bool)")?; + let args = vec![ + DynSolValue::Uint(pay_amt, 256), + DynSolValue::Address(pay_gem), + DynSolValue::Uint(buy_amt, 256), + DynSolValue::Address(buy_gem), + DynSolValue::Uint(U256::from(pos), 256), + DynSolValue::Bool(matching_enabled), + ]; + Ok(function.abi_encode_input(&args)?) +} diff --git a/utils/src/spammer.rs b/utils/src/spammer.rs index 1b0cd0b0..1928d28f 100644 --- a/utils/src/spammer.rs +++ b/utils/src/spammer.rs @@ -1,6 +1,6 @@ use core::fmt; use std::collections::HashMap; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use alloy_network::eip2718::Encodable2718; use alloy_primitives::Address; @@ -17,8 +17,12 @@ use tokio::sync::mpsc::{self, Receiver, Sender}; use tokio::time::{self, sleep, Duration, Instant}; use tracing::debug; +use crate::dex_templates::{RoundRobinSelector, TxTemplate}; use crate::make_signers; -use crate::tx::{make_signed_contract_call_tx, make_signed_eip1559_tx, make_signed_eip4844_tx}; +use crate::tx::{ + make_signed_contract_call_tx, make_signed_eip1559_tx, make_signed_eip4844_tx, + make_signed_tx_from_template, +}; /// Target pool size to maintain (in number of transactions). const TARGET_POOL_SIZE: u64 = 30_000; @@ -71,10 +75,18 @@ pub struct Spammer { chain_id: u64, /// Optional payload describing contract call spam parameters. contract_payload: Option, + /// Optional transaction templates for round-robin spamming. + /// Wrapped in Arc> to allow shared mutable access across tasks. + templates: Option>>, } impl Spammer { - pub fn new(url: Url, signer_index: usize, config: SpammerConfig) -> Result { + pub fn new( + url: Url, + signer_index: usize, + config: SpammerConfig, + templates: Option>, + ) -> Result { let signers = make_signers(); Ok(Self { id: signer_index.to_string(), @@ -87,6 +99,7 @@ impl Spammer { blobs: config.blobs, chain_id: config.chain_id, contract_payload: None, + templates: templates.map(|t| Arc::new(Mutex::new(RoundRobinSelector::new(t)))), }) } @@ -113,8 +126,9 @@ impl Spammer { max_rate: config.max_rate, batch_interval: config.batch_interval, blobs: false, // Contract calls don't use blobs - contract_payload: Some(contract_payload), chain_id: config.chain_id, + contract_payload: Some(contract_payload), + templates: None, }) } @@ -205,16 +219,12 @@ impl Spammer { let mut interval = time::interval(Duration::from_millis(self.batch_interval)); loop { - // Wait for next one-second tick. + // Wait for next tick let _ = interval.tick().await; let interval_start = Instant::now(); // Verify the nonce for gaps - // TODO: probably this should run as a separate task let on_chain_nonce = self.get_latest_nonce(address).await?; - // If the span between the on-chain nonce and the one we are about to send - // is too big, then probably there is a gap that doesn't allow the - // on-chain nonce too advance. let nonce_span = nonce.saturating_sub(on_chain_nonce); if nonce_span > self.max_rate { debug!("Current nonce={nonce}, on-chain nonce={on_chain_nonce}. Sending 10 txs"); @@ -228,7 +238,7 @@ impl Spammer { )); } - // Report individual results. + // Report individual results for ((_, tx_bytes_len), result) in batch_entries.into_iter().zip(results) { let mapped_result = result.map(|_| tx_bytes_len); result_sender.send(mapped_result).await?; @@ -322,7 +332,14 @@ impl Spammer { let mut next_nonce = nonce; for _ in 0..tx_count { - let signed_tx = if let Some(ref payload) = self.contract_payload { + let signed_tx = if let Some(ref templates) = self.templates { + // Use template-based transaction generation + let template = { + let mut selector = templates.lock().unwrap(); + selector.next_template().clone() + }; + make_signed_tx_from_template(&self.signer, &template, next_nonce).await? + } else if let Some(ref payload) = self.contract_payload { make_signed_contract_call_tx( &self.signer, next_nonce, diff --git a/utils/src/tx.rs b/utils/src/tx.rs index aaf8f04a..21cc4c4f 100644 --- a/utils/src/tx.rs +++ b/utils/src/tx.rs @@ -7,6 +7,11 @@ use alloy_signer_local::PrivateKeySigner; use color_eyre::eyre::{bail, Result}; use reth_primitives::{Transaction, TransactionSigned}; +use crate::dex_templates::{ + parse_address, parse_eth_value, parse_gwei_value, parse_input_data, Eip1559Template, + Eip4844Template, TxTemplate, +}; + pub(crate) fn make_eip4844_tx(nonce: u64, chain_id: u64) -> Transaction { Transaction::Eip4844(TxEip4844 { chain_id, @@ -114,6 +119,71 @@ pub(crate) async fn make_signed_contract_call_tx( sign_transaction(signer, tx).await } +// Template-based transaction generation + +pub(crate) fn make_eip1559_tx_from_template( + template: &Eip1559Template, + nonce: u64, +) -> Result { + let to = parse_address(&template.to)?; + let value = parse_eth_value(&template.value)?; + let max_fee_per_gas = parse_gwei_value(&template.max_fee_per_gas)?; + let max_priority_fee_per_gas = parse_gwei_value(&template.max_priority_fee_per_gas)?; + let input = parse_input_data(&template.input)?; + + Ok(Transaction::Eip1559(TxEip1559 { + chain_id: 1u64, + nonce, + max_priority_fee_per_gas, + max_fee_per_gas, + gas_limit: template.gas_limit, + to: to.into(), + value, + input, + access_list: Default::default(), + })) +} + +pub(crate) fn make_eip4844_tx_from_template( + template: &Eip4844Template, + nonce: u64, +) -> Result { + let to = parse_address(&template.to)?; + let value = parse_eth_value(&template.value)?; + let max_fee_per_gas = parse_gwei_value(&template.max_fee_per_gas)?; + let max_priority_fee_per_gas = parse_gwei_value(&template.max_priority_fee_per_gas)?; + let max_fee_per_blob_gas = parse_gwei_value(&template.max_fee_per_blob_gas)?; + + Ok(Transaction::Eip4844(TxEip4844 { + chain_id: 1u64, + nonce, + max_fee_per_gas, + max_priority_fee_per_gas, + gas_limit: template.gas_limit, + to, + value, + input: Bytes::default(), + access_list: Default::default(), + blob_versioned_hashes: vec![B256::random()], + max_fee_per_blob_gas, + })) +} + +pub(crate) async fn make_signed_tx_from_template( + signer: &PrivateKeySigner, + template: &TxTemplate, + nonce: u64, +) -> Result { + let tx = match template { + TxTemplate::Eip1559(t) => make_eip1559_tx_from_template(t, nonce)?, + TxTemplate::Eip4844(t) => make_eip4844_tx_from_template(t, nonce)?, + }; + + let tx_sign_hash = tx.signature_hash(); + let signature = signer.sign_hash(&tx_sign_hash).await?; + Ok(TransactionSigned::new_unhashed(tx, signature)) +} + #[cfg(test)] mod tests { use alloy_network::eip2718::Encodable2718; diff --git a/utils/utils/examples/generated_rubicon.yaml b/utils/utils/examples/generated_rubicon.yaml new file mode 100644 index 00000000..3244317d --- /dev/null +++ b/utils/utils/examples/generated_rubicon.yaml @@ -0,0 +1,155 @@ +transactions: +- type: eip1559 + to: 0x4b6ab5f819a515382b0deb6935d793817bb4af28 + value: '0.0' + gas_limit: 100000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0x095ea7b3000000000000000000000000d5ac451b0c50b9476107823af206ed814a2e2580ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +- type: eip1559 + to: 0x99b9b29b0b3e9542c6279615a960728380fd2ce4 + value: '0.0' + gas_limit: 100000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0x095ea7b3000000000000000000000000d5ac451b0c50b9476107823af206ed814a2e2580ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +- type: eip1559 + to: 0x4b6ab5f819a515382b0deb6935d793817bb4af28 + value: '0.1' + gas_limit: 100000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: '0xd0e30db0' +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af28000000000000000000000000000000000000000000000001a055690d9db8000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0x4b6ab5f819a515382b0deb6935d793817bb4af28 + value: '1' + gas_limit: 100000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: '0xd0e30db0' +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af28000000000000000000000000000000000000000000000001ae361fc1451c000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000199650db3ca06000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af28000000000000000000000000000000000000000000000001a055690d9db8000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af28000000000000000000000000000000000000000000000001a745c467716a000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af280000000000000000000000000000000000000000000000019274b259f654000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af28000000000000000000000000000000000000000000000001b5267b1b18ce000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af280000000000000000000000000000000000000000000000018b84570022a2000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af28000000000000000000000000000000000000000000000001bc16d674ec80000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af280000000000000000000000000000000000000000000000019d8ede1ce2a4000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0x99b9b29b0b3e9542c6279615a960728380fd2ce4 + value: '0.0' + gas_limit: 200000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: '0xde5f72fd' +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000001a055690d9db8000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce4000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000001ae361fc1451c000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce4000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f01400000000000000000000000000000000000000000000000199650db3ca06000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce4000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000001a055690d9db8000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce4000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000001a745c467716a000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce4000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000001b5267b1b18ce000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce4000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +- type: eip1559 + to: 0xd5ac451b0c50b9476107823af206ed814a2e2580 + value: '0.0' + gas_limit: 1500000 + max_fee_per_gas: '2' + max_priority_fee_per_gas: '1' + input: 0xe1a6f014000000000000000000000000000000000000000000000001bc16d674ec80000000000000000000000000000099b9b29b0b3e9542c6279615a960728380fd2ce4000000000000000000000000000000000000000000000000002386f26fc100000000000000000000000000004b6ab5f819a515382b0deb6935d793817bb4af2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001