diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..9818407 --- /dev/null +++ b/.env.example @@ -0,0 +1,16 @@ +# Environment variables for docker-compose +# Copy this file to .env and adjust values as needed + +# ClickHouse Configuration +CLICKHOUSE_DB=indexer +CLICKHOUSE_USER=indexer +CLICKHOUSE_PASSWORD=indexer + +# Indexer Configuration +CHAIN_ID=1 +START_BLOCK=0 +BATCH_SIZE=10 +RPC_URL=https://eth.llamarpc.com +DEBUG=true +FETCH_UNCLES=false +TRACES=true diff --git a/Cargo.lock b/Cargo.lock index a5eaef3..0d33c37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,16 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - [[package]] name = "addr2line" version = "0.24.2" @@ -28,23 +18,597 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] -name = "aes" -version = "0.8.4" +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "alloy" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ba1c79677c9ce51c8d45e20845b05e6fb070ea2c863fba03ad6af2c778474bd" +dependencies = [ + "alloy-consensus", + "alloy-contract", + "alloy-core", + "alloy-eips", + "alloy-genesis", + "alloy-json-rpc", + "alloy-network", + "alloy-node-bindings", + "alloy-provider", + "alloy-pubsub", + "alloy-rpc-client", + "alloy-rpc-types", + "alloy-serde", + "alloy-signer", + "alloy-signer-local", + "alloy-transport", + "alloy-transport-http", + "alloy-transport-ipc", + "alloy-transport-ws", +] + +[[package]] +name = "alloy-chains" +version = "0.1.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28e2652684758b0d9b389d248b209ed9fd9989ef489a550265fe4bb8454fe7eb" +dependencies = [ + "alloy-primitives 0.8.26", + "num_enum", + "strum", +] + +[[package]] +name = "alloy-consensus" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da374e868f54c7f4ad2ad56829827badca388efd645f8cf5fccc61c2b5343504" +dependencies = [ + "alloy-eips", + "alloy-primitives 0.7.7", + "alloy-rlp", + "alloy-serde", + "c-kzg", + "serde", +] + +[[package]] +name = "alloy-contract" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dc6957ff706f9e5f6fd42f52a93e4bce476b726c92d077b348de28c4a76730c" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-network", + "alloy-primitives 0.7.7", + "alloy-provider", + "alloy-pubsub", + "alloy-rpc-types-eth", + "alloy-sol-types", + "alloy-transport", + "futures", + "futures-util", + "thiserror 1.0.69", +] + +[[package]] +name = "alloy-core" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "529fc6310dc1126c8de51c376cbc59c79c7f662bd742be7dc67055d5421a81b4" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-primitives 0.7.7", + "alloy-sol-types", +] + +[[package]] +name = "alloy-dyn-abi" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413902aa18a97569e60f679c23f46a18db1656d87ab4d4e49d0e1e52042f66df" +dependencies = [ + "alloy-json-abi", + "alloy-primitives 0.7.7", + "alloy-sol-type-parser", + "alloy-sol-types", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow", +] + +[[package]] +name = "alloy-eips" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76ecab54890cdea1e4808fc0891c7e6cfcf71fe1a9fe26810c7280ef768f4ed" +dependencies = [ + "alloy-primitives 0.7.7", + "alloy-rlp", + "alloy-serde", + "c-kzg", + "derive_more 0.99.20", + "once_cell", + "serde", + "sha2", +] + +[[package]] +name = "alloy-genesis" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca15afde1b6d15e3fc1c97421262b1bbb37aee45752e3c8b6d6f13f776554ff" +dependencies = [ + "alloy-primitives 0.7.7", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-json-abi" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc05b04ac331a9f07e3a4036ef7926e49a8bf84a99a1ccfc7e2ab55a5fcbb372" +dependencies = [ + "alloy-primitives 0.7.7", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d6f34930b7e3e2744bcc79056c217f00cb2abb33bc5d4ff88da7623c5bb078b" +dependencies = [ + "alloy-primitives 0.7.7", + "serde", + "serde_json", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "alloy-network" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f6895fc31b48fa12306ef9b4f78b7764f8bd6d7d91cdb0a40e233704a0f23f" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-primitives 0.7.7", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", + "alloy-sol-types", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "thiserror 1.0.69", +] + +[[package]] +name = "alloy-node-bindings" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494b2fb0276a78ec13791446a417c2517eee5c8e8a8c520ae0681975b8056e5c" +dependencies = [ + "alloy-genesis", + "alloy-primitives 0.7.7", + "k256", + "serde_json", + "tempfile", + "thiserror 1.0.69", + "tracing", + "url", +] + +[[package]] +name = "alloy-primitives" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccb3ead547f4532bc8af961649942f0b9c16ee9226e26caa3f38420651cc0bf4" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more 0.99.20", + "hex-literal", + "itoa", + "k256", + "keccak-asm", + "proptest", + "rand 0.8.5", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-primitives" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777d58b30eb9a4db0e5f59bc30e8c2caef877fee7dc8734cf242a51a60f22e05" +dependencies = [ + "bytes", + "cfg-if", + "const-hex", + "derive_more 2.0.1", + "itoa", + "paste", + "ruint", + "tiny-keccak", +] + +[[package]] +name = "alloy-provider" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c538bfa893d07e27cb4f3c1ab5f451592b7c526d511d62b576a2ce59e146e4a" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-node-bindings", + "alloy-primitives 0.7.7", + "alloy-pubsub", + "alloy-rpc-client", + "alloy-rpc-types-anvil", + "alloy-rpc-types-eth", + "alloy-signer-local", + "alloy-transport", + "alloy-transport-http", + "alloy-transport-ipc", + "alloy-transport-ws", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "futures", + "futures-utils-wasm", + "lru", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "alloy-pubsub" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a7341322d9bc0e49f6e9fd9f2eb8e30f73806f2dd12cbb3d6bab2694c921f87" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives 0.7.7", + "alloy-transport", + "bimap", + "futures", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tracing", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f70d83b765fdc080dbcd4f4db70d8d23fe4761f2f02ebfa9146b833900634b4" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", +] + +[[package]] +name = "alloy-rpc-client" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ba31bae67773fd5a60020bea900231f8396202b7feca4d0c70c6b59308ab4a8" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives 0.7.7", + "alloy-pubsub", + "alloy-transport", + "alloy-transport-http", + "alloy-transport-ipc", + "alloy-transport-ws", + "futures", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tracing", + "url", +] + +[[package]] +name = "alloy-rpc-types" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "184a7a42c7ba9141cc9e76368356168c282c3bc3d9e5d78f3556bdfe39343447" +dependencies = [ + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", + "alloy-serde", +] + +[[package]] +name = "alloy-rpc-types-anvil" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7cf4356a9d00df76d6e90d002e2a7b5edc1c8476e90e6f17ab868d99db6435" +dependencies = [ + "alloy-primitives 0.7.7", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-rpc-types-engine" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e765962e3b82fd6f276a0873b5bd897e5d75a25f78fa9a6a21bd350d8e98a4e" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.7.7", + "alloy-rlp", + "alloy-rpc-types-eth", + "alloy-serde", + "jsonwebtoken", + "rand 0.8.5", + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4123ee21f99ba4bd31bfa36ba89112a18a500f8b452f02b35708b1b951e2b9" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.7.7", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types", + "itertools 0.13.0", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "alloy-rpc-types-trace" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567933b1d95fd42cb70b75126e32afec2e5e2c3c16e7100a3f83dc1c80f4dc0e" +dependencies = [ + "alloy-primitives 0.7.7", + "alloy-rpc-types-eth", + "alloy-serde", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "alloy-serde" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9416c52959e66ead795a11f4a86c248410e9e368a0765710e57055b8a1774dd6" +dependencies = [ + "alloy-primitives 0.7.7", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-signer" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33753c09fa1ad85e5b092b8dc2372f1e337a42e84b9b4cff9fede75ba4adb32" +dependencies = [ + "alloy-primitives 0.7.7", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror 1.0.69", +] + +[[package]] +name = "alloy-signer-local" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dfc9c26fe6c6f1bad818c9a976de9044dd12e1f75f1f156a801ee3e8148c1b6" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives 0.7.7", + "alloy-signer", + "async-trait", + "k256", + "rand 0.8.5", + "thiserror 1.0.69", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b40397ddcdcc266f59f959770f601ce1280e699a91fc1862f29cef91707cd09" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.94", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "867a5469d61480fea08c7333ffeca52d5b621f5ca2e44f271b117ec1fc9a0525" +dependencies = [ + "alloy-json-abi", + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap 2.7.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.94", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e482dc33a32b6fadbc0f599adea520bd3aaa585c141a80b404d0a3e3fa72528" +dependencies = [ + "alloy-json-abi", + "const-hex", + "dunce", + "heck", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.94", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbcba3ca07cf7975f15d871b721fb18031eec8bce51103907f6dcce00b255d98" +dependencies = [ + "serde", + "winnow", +] + +[[package]] +name = "alloy-sol-types" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a91ca40fa20793ae9c3841b83e74569d1cc9af29a2f5237314fd3452d51e38c7" +dependencies = [ + "alloy-json-abi", + "alloy-primitives 0.7.7", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01b51a291f949f755e6165c3ed562883175c97423703703355f4faa4b7d0a57c" +dependencies = [ + "alloy-json-rpc", + "base64", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tower 0.4.13", + "tracing", + "url", +] + +[[package]] +name = "alloy-transport-http" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d65871f9f1cafe1ed25cde2f1303be83e6473e995a2d56c275ae4fcce6119c" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "reqwest", + "serde_json", + "tower 0.4.13", + "tracing", + "url", +] + +[[package]] +name = "alloy-transport-ipc" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +checksum = "cd7fbc8b6282ce41b01cbddef7bffb133fe6e1bf65dcd39770d45a905c051179" dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", + "alloy-json-rpc", + "alloy-pubsub", + "alloy-transport", + "bytes", + "futures", + "interprocess", + "pin-project", + "serde_json", + "tokio", + "tokio-util", + "tracing", ] [[package]] -name = "aho-corasick" -version = "1.1.3" +name = "alloy-transport-ws" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "aec83fd052684556c78c54df111433493267234d82321c2236560c752f595f20" dependencies = [ - "memchr", + "alloy-pubsub", + "alloy-transport", + "futures", + "http", + "rustls", + "serde_json", + "tokio", + "tokio-tungstenite", + "tracing", + "ws_stream_wasm", ] [[package]] @@ -112,12 +676,192 @@ dependencies = [ ] [[package]] -name = "array-bytes" -version = "9.1.2" +name = "ark-ff" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4449507daf4f07a8c8309e122d32a53d15c9f33e77eaf01c839fea42ccd4d673" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" dependencies = [ - "smallvec", + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.94", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.94", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", ] [[package]] @@ -127,12 +871,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] -name = "ascii-canvas" -version = "3.0.0" +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ - "term", + "proc-macro2", + "quote", + "syn 2.0.94", ] [[package]] @@ -154,7 +911,7 @@ checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" dependencies = [ "futures", "pharos", - "rustc_version", + "rustc_version 0.4.1", ] [[package]] @@ -201,18 +958,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -226,31 +971,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] -name = "bech32" -version = "0.9.1" +name = "bimap" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" [[package]] name = "bit-set" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" @@ -280,13 +1019,15 @@ dependencies = [ ] [[package]] -name = "bs58" -version = "0.5.1" +name = "blst" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" dependencies = [ - "sha2", - "tinyvec", + "cc", + "glob", + "threadpool", + "zeroize", ] [[package]] @@ -318,64 +1059,26 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" dependencies = [ "serde", ] [[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" +name = "c-kzg" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" dependencies = [ + "blst", "cc", + "glob", + "hex", "libc", - "pkg-config", -] - -[[package]] -name = "camino" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver", + "once_cell", "serde", - "serde_json", - "thiserror", ] [[package]] @@ -384,17 +1087,9 @@ version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7" dependencies = [ - "jobserver", - "libc", "shlex", ] -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - [[package]] name = "cfg-if" version = "1.0.0" @@ -414,16 +1109,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "cityhash-rs" version = "1.0.1" @@ -472,34 +1157,36 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "clickhouse" -version = "0.13.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2135bb9638e8c8c1e3d794f242099e57987059ba52e7e3de597e1d99b2c4a5a3" +checksum = "52d6ac02411e84914fdf4e0565bfe02fc4bebdf375bd1fc58168bad74b3707a2" dependencies = [ "bstr", "bytes", "cityhash-rs", - "clickhouse-derive", - "futures", + "clickhouse-macros", + "clickhouse-types", "futures-channel", + "futures-util", "http-body-util", - "hyper 1.5.2", + "hyper", + "hyper-tls", "hyper-util", "lz4_flex", "replace_with", "sealed", "serde", "static_assertions", - "thiserror", + "thiserror 2.0.17", "tokio", "url", ] [[package]] -name = "clickhouse-derive" -version = "0.2.0" +name = "clickhouse-macros" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d70f3e2893f7d3e017eeacdc9a708fbc29a10488e3ebca21f9df6a5d2b616dbb" +checksum = "ff6669899e23cb87b43daf7996f0ea3b9c07d0fb933d745bb7b815b052515ae3" dependencies = [ "proc-macro2", "quote", @@ -508,55 +1195,13 @@ dependencies = [ ] [[package]] -name = "coins-bip32" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" -dependencies = [ - "bs58", - "coins-core", - "digest", - "hmac", - "k256", - "serde", - "sha2", - "thiserror", -] - -[[package]] -name = "coins-bip39" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" -dependencies = [ - "bitvec", - "coins-bip32", - "hmac", - "once_cell", - "pbkdf2 0.12.2", - "rand", - "sha2", - "thiserror", -] - -[[package]] -name = "coins-core" -version = "0.8.7" +name = "clickhouse-types" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +checksum = "235f72141cfbe1d2d930d8156a34814c8a3d60491febb9af64cc52a203444764" dependencies = [ - "base64 0.21.7", - "bech32", - "bs58", - "digest", - "generic-array", - "hex", - "ripemd", - "serde", - "serde_derive", - "sha2", - "sha3", - "thiserror", + "bytes", + "thiserror 2.0.17", ] [[package]] @@ -569,20 +1214,10 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" name = "colored" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" -dependencies = [ - "lazy_static", - "windows-sys 0.59.0", -] - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ - "bytes", - "memchr", + "lazy_static", + "windows-sys 0.59.0", ] [[package]] @@ -605,10 +1240,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] -name = "constant_time_eq" -version = "0.1.5" +name = "convert_case" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation" @@ -635,40 +1270,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - [[package]] name = "crunchy" version = "0.2.2" @@ -682,7 +1283,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -697,15 +1298,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - [[package]] name = "darling" version = "0.20.10" @@ -741,6 +1333,19 @@ dependencies = [ "syn 2.0.94", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.6.0" @@ -768,77 +1373,69 @@ dependencies = [ ] [[package]] -name = "derive_more" -version = "1.0.0" +name = "derivative" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "derive_more-impl", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "derive_more-impl" -version = "1.0.0" +name = "derive_more" +version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ + "convert_case", "proc-macro2", "quote", + "rustc_version 0.4.1", "syn 2.0.94", ] [[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs" -version = "5.0.1" +name = "derive_more" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" dependencies = [ - "dirs-sys", + "derive_more-impl", ] [[package]] -name = "dirs-next" -version = "2.0.0" +name = "derive_more-impl" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ - "cfg-if", - "dirs-sys-next", + "proc-macro2", + "quote", + "syn 2.0.94", + "unicode-xid", ] [[package]] -name = "dirs-sys" -version = "0.4.1" +name = "digest" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", + "generic-array", ] [[package]] -name = "dirs-sys-next" -version = "0.1.2" +name = "digest" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "libc", - "redox_users", - "winapi", + "block-buffer", + "const-oid", + "crypto-common", + "subtle", ] [[package]] @@ -852,6 +1449,12 @@ dependencies = [ "syn 2.0.94", ] +[[package]] +name = "doctest-file" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" + [[package]] name = "dunce" version = "1.0.5" @@ -865,13 +1468,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", - "digest", + "digest 0.10.7", "elliptic-curve", "rfc6979", "signature", "spki", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.94", +] + [[package]] name = "either" version = "1.13.0" @@ -886,405 +1501,76 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest", + "digest 0.10.7", "ff", "generic-array", "group", "pkcs8", - "rand_core", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "ena" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" -dependencies = [ - "log", -] - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "enr" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" -dependencies = [ - "base64 0.21.7", - "bytes", - "hex", - "k256", - "log", - "rand", - "rlp", - "serde", - "sha3", - "zeroize", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "eth-keystore" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" -dependencies = [ - "aes", - "ctr", - "digest", - "hex", - "hmac", - "pbkdf2 0.11.0", - "rand", - "scrypt", - "serde", - "serde_json", - "sha2", - "sha3", - "thiserror", - "uuid", -] - -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", - "scale-info", - "uint", -] - -[[package]] -name = "ethers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816841ea989f0c69e459af1cf23a6b0033b19a55424a1ea3a30099becdb8dec0" -dependencies = [ - "ethers-addressbook", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-middleware", - "ethers-providers", - "ethers-signers", - "ethers-solc", -] - -[[package]] -name = "ethers-addressbook" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5495afd16b4faa556c3bba1f21b98b4983e53c1755022377051a975c3b021759" -dependencies = [ - "ethers-core", - "once_cell", - "serde", - "serde_json", -] - -[[package]] -name = "ethers-contract" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" -dependencies = [ - "const-hex", - "ethers-contract-abigen", - "ethers-contract-derive", - "ethers-core", - "ethers-providers", - "futures-util", - "once_cell", - "pin-project", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "ethers-contract-abigen" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" -dependencies = [ - "Inflector", - "const-hex", - "dunce", - "ethers-core", - "ethers-etherscan", - "eyre", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "reqwest", - "serde", - "serde_json", - "syn 2.0.94", - "toml", - "walkdir", -] - -[[package]] -name = "ethers-contract-derive" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" -dependencies = [ - "Inflector", - "const-hex", - "ethers-contract-abigen", - "ethers-core", - "proc-macro2", - "quote", - "serde_json", - "syn 2.0.94", -] - -[[package]] -name = "ethers-core" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" -dependencies = [ - "arrayvec", - "bytes", - "cargo_metadata", - "chrono", - "const-hex", - "elliptic-curve", - "ethabi", - "generic-array", - "k256", - "num_enum", - "once_cell", - "open-fastrlp", - "rand", - "rlp", - "serde", - "serde_json", - "strum", - "syn 2.0.94", - "tempfile", - "thiserror", - "tiny-keccak", - "unicode-xid", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", ] [[package]] -name = "ethers-etherscan" -version = "2.0.14" +name = "encoding_rs" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79e5973c26d4baf0ce55520bd732314328cabe53193286671b47144145b9649" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "chrono", - "ethers-core", - "reqwest", - "semver", - "serde", - "serde_json", - "thiserror", - "tracing", + "cfg-if", ] [[package]] -name = "ethers-middleware" -version = "2.0.14" +name = "enum-ordinalize" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f9fdf09aec667c099909d91908d5eaf9be1bd0e2500ba4172c1d28bfaa43de" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" dependencies = [ - "async-trait", - "auto_impl", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-providers", - "ethers-signers", - "futures-channel", - "futures-locks", - "futures-util", - "instant", - "reqwest", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", - "tracing-futures", - "url", + "enum-ordinalize-derive", ] [[package]] -name = "ethers-providers" -version = "2.0.14" +name = "enum-ordinalize-derive" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ - "async-trait", - "auto_impl", - "base64 0.21.7", - "bytes", - "const-hex", - "enr", - "ethers-core", - "futures-core", - "futures-timer", - "futures-util", - "hashers", - "http 0.2.12", - "instant", - "jsonwebtoken", - "once_cell", - "pin-project", - "reqwest", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-tungstenite", - "tracing", - "tracing-futures", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "ws_stream_wasm", + "proc-macro2", + "quote", + "syn 2.0.94", ] [[package]] -name = "ethers-signers" -version = "2.0.14" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228875491c782ad851773b652dd8ecac62cda8571d3bc32a5853644dd26766c2" -dependencies = [ - "async-trait", - "coins-bip32", - "coins-bip39", - "const-hex", - "elliptic-curve", - "eth-keystore", - "ethers-core", - "rand", - "sha2", - "thiserror", - "tracing", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "ethers-solc" -version = "2.0.14" +name = "errno" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66244a771d9163282646dbeffe0e6eca4dda4146b6498644e678ac6089b11edd" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ - "cfg-if", - "const-hex", - "dirs", - "dunce", - "ethers-core", - "glob", - "home", - "md-5", - "num_cpus", - "once_cell", - "path-slash", - "rayon", - "regex", - "semver", - "serde", - "serde_json", - "solang-parser", - "svm-rs", - "thiserror", - "tiny-keccak", - "tokio", - "tracing", - "walkdir", - "yansi", + "libc", + "windows-sys 0.59.0", ] [[package]] name = "evm-indexer" -version = "1.5.1" +version = "2.0.0" dependencies = [ - "array-bytes", + "alloy", + "alloy-rpc-types-trace", "clap", "clickhouse", - "ethers", "futures", "hex", - "jsonrpsee", - "jsonrpsee-http-client", - "jsonrpsee-ws-client", "log", - "primitive-types", - "rand", + "rand 0.8.5", + "reqwest", "serde", - "serde_bytes", "serde_json", "serde_repr", "serde_with", @@ -1294,20 +1580,32 @@ dependencies = [ ] [[package]] -name = "eyre" -version = "0.6.12" +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fastrlp" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ - "indenter", - "once_cell", + "arrayvec", + "auto_impl", + "bytes", ] [[package]] -name = "fastrand" -version = "2.3.0" +name = "fastrlp" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] [[package]] name = "ff" @@ -1315,7 +1613,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1326,32 +1624,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand", + "rand 0.8.5", "rustc-hex", "static_assertions", ] [[package]] -name = "fixedbitset" -version = "0.4.2" +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] -name = "flate2" -version = "1.0.35" +name = "foreign-types" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "crc32fast", - "miniz_oxide", + "foreign-types-shared", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "foreign-types-shared" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" @@ -1362,16 +1665,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "funty" version = "2.0.0" @@ -1426,16 +1719,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" -[[package]] -name = "futures-locks" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" -dependencies = [ - "futures-channel", - "futures-task", -] - [[package]] name = "futures-macro" version = "0.3.31" @@ -1459,16 +1742,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" -dependencies = [ - "gloo-timers", - "send_wrapper 0.4.0", -] - [[package]] name = "futures-util" version = "0.3.31" @@ -1488,13 +1761,10 @@ dependencies = [ ] [[package]] -name = "fxhash" -version = "0.2.1" +name = "futures-utils-wasm" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" [[package]] name = "generic-array" @@ -1514,8 +1784,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", ] [[package]] @@ -1530,18 +1814,6 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "group" version = "0.13.0" @@ -1549,41 +1821,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] [[package]] name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.7.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.7" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.2.0", + "http", "indexmap 2.7.0", "slab", "tokio", @@ -1599,17 +1852,19 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] -name = "hashers" -version = "1.0.1" +name = "hashbrown" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ - "fxhash", + "allocator-api2", + "equivalent", + "foldhash", ] [[package]] @@ -1629,34 +1884,23 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "serde", ] [[package]] -name = "home" -version = "0.5.11" +name = "hex-literal" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] -name = "http" -version = "0.2.12" +name = "hmac" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "bytes", - "fnv", - "itoa", + "digest 0.10.7", ] [[package]] @@ -1670,17 +1914,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -1688,7 +1921,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.2.0", + "http", ] [[package]] @@ -1699,8 +1932,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.2.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -1710,36 +1943,6 @@ version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.5.2" @@ -1749,11 +1952,10 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.7", - "http 1.2.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -1763,33 +1965,33 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.32", - "rustls 0.21.12", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls", + "tower-service", ] [[package]] -name = "hyper-rustls" -version = "0.27.5" +name = "hyper-tls" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ - "futures-util", - "http 1.2.0", - "hyper 1.5.2", + "bytes", + "http-body-util", + "hyper", "hyper-util", - "log", - "rustls 0.23.20", - "rustls-pki-types", + "native-tls", "tokio", - "tokio-rustls 0.26.1", + "tokio-native-tls", "tower-service", ] @@ -1802,9 +2004,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.2.0", - "http-body 1.0.1", - "hyper 1.5.2", + "http", + "http-body", + "hyper", "pin-project-lite", "socket2", "tokio", @@ -1981,30 +2183,12 @@ dependencies = [ ] [[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" +name = "impl-codec" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "serde", + "parity-scale-codec", ] [[package]] @@ -2018,12 +2202,6 @@ dependencies = [ "syn 2.0.94", ] -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - [[package]] name = "indexmap" version = "1.9.3" @@ -2047,21 +2225,18 @@ dependencies = [ ] [[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.13" +name = "interprocess" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +checksum = "d941b405bd2322993887859a8ee6ac9134945a24ec5ec763a8a962fc64dfec2d" dependencies = [ - "cfg-if", + "doctest-file", + "futures-core", + "libc", + "recvmsg", + "tokio", + "widestring", + "windows-sys 0.52.0", ] [[package]] @@ -2078,47 +2253,27 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" -version = "0.11.0" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] -name = "itoa" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" - -[[package]] -name = "jni" -version = "0.19.0" +name = "itertools" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", + "either", ] [[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jobserver" -version = "0.1.32" +name = "itoa" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" @@ -2130,168 +2285,16 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "jsonrpsee" -version = "0.24.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5c71d8c1a731cc4227c2f698d377e7848ca12c8a48866fc5e6951c43a4db843" -dependencies = [ - "jsonrpsee-core", - "jsonrpsee-proc-macros", - "jsonrpsee-server", - "jsonrpsee-types", - "tokio", - "tracing", -] - -[[package]] -name = "jsonrpsee-client-transport" -version = "0.24.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "548125b159ba1314104f5bb5f38519e03a41862786aa3925cf349aae9cdd546e" -dependencies = [ - "base64 0.22.1", - "futures-util", - "http 1.2.0", - "jsonrpsee-core", - "pin-project", - "rustls 0.23.20", - "rustls-pki-types", - "rustls-platform-verifier", - "soketto", - "thiserror", - "tokio", - "tokio-rustls 0.26.1", - "tokio-util", - "tracing", - "url", -] - -[[package]] -name = "jsonrpsee-core" -version = "0.24.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2882f6f8acb9fdaec7cefc4fd607119a9bd709831df7d7672a1d3b644628280" -dependencies = [ - "async-trait", - "bytes", - "futures-timer", - "futures-util", - "http 1.2.0", - "http-body 1.0.1", - "http-body-util", - "jsonrpsee-types", - "parking_lot", - "pin-project", - "rand", - "rustc-hash", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-stream", - "tracing", -] - -[[package]] -name = "jsonrpsee-http-client" -version = "0.24.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" -dependencies = [ - "async-trait", - "base64 0.22.1", - "http-body 1.0.1", - "hyper 1.5.2", - "hyper-rustls 0.27.5", - "hyper-util", - "jsonrpsee-core", - "jsonrpsee-types", - "rustls 0.23.20", - "rustls-platform-verifier", - "serde", - "serde_json", - "thiserror", - "tokio", - "tower", - "tracing", - "url", -] - -[[package]] -name = "jsonrpsee-proc-macros" -version = "0.24.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" -dependencies = [ - "heck", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.94", -] - -[[package]] -name = "jsonrpsee-server" -version = "0.24.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ad8ddc14be1d4290cd68046e7d1d37acd408efed6d3ca08aefcc3ad6da069c" -dependencies = [ - "futures-util", - "http 1.2.0", - "http-body 1.0.1", - "http-body-util", - "hyper 1.5.2", - "hyper-util", - "jsonrpsee-core", - "jsonrpsee-types", - "pin-project", - "route-recognizer", - "serde", - "serde_json", - "soketto", - "thiserror", - "tokio", - "tokio-stream", - "tokio-util", - "tower", - "tracing", -] - -[[package]] -name = "jsonrpsee-types" -version = "0.24.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1" -dependencies = [ - "http 1.2.0", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "jsonrpsee-ws-client" -version = "0.24.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fe322e0896d0955a3ebdd5bf813571c53fea29edd713bc315b76620b327e86d" -dependencies = [ - "http 1.2.0", - "jsonrpsee-client-transport", - "jsonrpsee-core", - "jsonrpsee-types", - "url", -] - [[package]] name = "jsonwebtoken" -version = "8.3.0" +version = "9.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" dependencies = [ - "base64 0.21.7", + "base64", + "js-sys", "pem", - "ring 0.16.20", + "ring", "serde", "serde_json", "simple_asn1", @@ -2308,46 +2311,16 @@ dependencies = [ "elliptic-curve", "once_cell", "sha2", - "signature", -] - -[[package]] -name = "keccak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lalrpop" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" -dependencies = [ - "ascii-canvas", - "bit-set", - "ena", - "itertools", - "lalrpop-util", - "petgraph", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", - "walkdir", ] [[package]] -name = "lalrpop-util" -version = "0.20.2" +name = "keccak-asm" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" dependencies = [ - "regex-automata", + "digest 0.10.7", + "sha3-asm", ] [[package]] @@ -2363,14 +2336,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] -name = "libredox" -version = "0.1.3" +name = "libm" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.6.0", - "libc", -] +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "linux-raw-sys" @@ -2401,20 +2370,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] -name = "lz4_flex" -version = "0.11.3" +name = "lru" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.2", +] [[package]] -name = "md-5" -version = "0.10.6" +name = "lz4_flex" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] +checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" [[package]] name = "memchr" @@ -2449,10 +2417,21 @@ dependencies = [ ] [[package]] -name = "new_debug_unreachable" -version = "1.0.6" +name = "native-tls" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] [[package]] name = "num-bigint" @@ -2486,6 +2465,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2513,7 +2493,6 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.94", @@ -2535,28 +2514,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] -name = "open-fastrlp" -version = "0.1.4" +name = "openssl" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "arrayvec", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", ] [[package]] -name = "open-fastrlp-derive" +name = "openssl-macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "bytes", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.94", ] [[package]] @@ -2566,10 +2546,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] -name = "option-ext" -version = "0.2.0" +name = "openssl-sys" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] [[package]] name = "parity-scale-codec" @@ -2608,141 +2594,58 @@ dependencies = [ ] [[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "path-slash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest", - "hmac", - "password-hash", - "sha2", -] - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.7.0", -] - -[[package]] -name = "pharos" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" -dependencies = [ - "futures", - "rustc_version", -] - -[[package]] -name = "phf" -version = "0.11.2" +name = "parking_lot_core" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "phf_macros", - "phf_shared 0.11.2", + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", ] [[package]] -name = "phf_generator" -version = "0.11.2" +name = "paste" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand", -] +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] -name = "phf_macros" -version = "0.11.2" +name = "pem" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ - "phf_generator", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn 2.0.94", + "base64", + "serde_core", ] [[package]] -name = "phf_shared" -version = "0.10.0" +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" dependencies = [ - "siphasher", + "memchr", + "ucd-trie", ] [[package]] -name = "phf_shared" -version = "0.11.2" +name = "pharos" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ - "siphasher", + "futures", + "rustc_version 0.4.1", ] [[package]] @@ -2808,22 +2711,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "prettyplease" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" -dependencies = [ - "proc-macro2", - "syn 2.0.94", -] - [[package]] name = "primitive-types" version = "0.12.2" @@ -2832,9 +2719,6 @@ checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", "uint", ] @@ -2847,6 +2731,30 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.92" @@ -2862,16 +2770,26 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ - "bitflags 2.6.0", + "bit-set", + "bit-vec", + "bitflags", "lazy_static", "num-traits", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "rand_xorshift", "regex-syntax", + "rusty-fork", + "tempfile", "unarray", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.38" @@ -2881,6 +2799,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "radium" version = "0.7.0" @@ -2894,99 +2818,80 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "rand" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "getrandom", + "rand_chacha 0.9.0", + "rand_core 0.9.3", ] [[package]] -name = "rand_xorshift" -version = "0.3.0" +name = "rand_chacha" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ - "rand_core", + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] -name = "rayon" -version = "1.10.0" +name = "rand_chacha" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ - "either", - "rayon-core", + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] -name = "rayon-core" -version = "1.12.1" +name = "rand_core" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "crossbeam-deque", - "crossbeam-utils", + "getrandom 0.2.15", ] [[package]] -name = "redox_syscall" -version = "0.5.8" +name = "rand_core" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "bitflags 2.6.0", + "getrandom 0.3.4", ] [[package]] -name = "redox_users" -version = "0.4.6" +name = "rand_xorshift" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "getrandom", - "libredox", - "thiserror", + "rand_core 0.6.4", ] [[package]] -name = "regex" -version = "1.11.1" +name = "recvmsg" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] +checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" [[package]] -name = "regex-automata" -version = "0.4.9" +name = "redox_syscall" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", + "bitflags", ] [[package]] @@ -3003,43 +2908,46 @@ checksum = "e3a8614ee435691de62bcffcf4a66d91b3594bf1428a5722e79103249a095690" [[package]] name = "reqwest" -version = "0.11.27" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ - "base64 0.21.7", + "base64", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", - "hyper-rustls 0.24.2", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "system-configuration", "tokio", - "tokio-rustls 0.24.1", + "tokio-native-tls", + "tower 0.5.2", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.25.4", - "winreg", + "windows-registry", ] [[package]] @@ -3052,21 +2960,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - [[package]] name = "ring" version = "0.17.8" @@ -3075,22 +2968,13 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", - "spin 0.9.8", - "untrusted 0.9.0", + "spin", + "untrusted", "windows-sys 0.52.0", ] -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest", -] - [[package]] name = "rlp" version = "0.5.2" @@ -3098,26 +2982,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ "bytes", - "rlp-derive", "rustc-hex", ] [[package]] -name = "rlp-derive" -version = "0.1.0" +name = "ruint" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "ark-ff 0.5.0", + "bytes", + "fastrlp 0.3.1", + "fastrlp 0.4.0", + "num-bigint", + "num-integer", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand 0.8.5", + "rand 0.9.2", + "rlp", + "ruint-macro", + "serde_core", + "valuable", + "zeroize", ] [[package]] -name = "route-recognizer" -version = "0.3.1" +name = "ruint-macro" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rustc-demangle" @@ -3126,16 +3026,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] -name = "rustc-hash" +name = "rustc-hex" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" [[package]] -name = "rustc-hex" -version = "2.1.0" +name = "rustc_version" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] [[package]] name = "rustc_version" @@ -3143,7 +3046,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver", + "semver 1.0.24", ] [[package]] @@ -3152,62 +3055,27 @@ version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ - "bitflags 2.6.0", + "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys 0.59.0", ] -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring 0.17.8", - "rustls-webpki 0.101.7", - "sct", -] - [[package]] name = "rustls" version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ - "log", "once_cell", - "ring 0.17.8", + "ring", "rustls-pki-types", - "rustls-webpki 0.102.8", + "rustls-webpki", "subtle", "zeroize", ] -[[package]] -name = "rustls-native-certs" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" -dependencies = [ - "openssl-probe", - "rustls-pemfile 2.2.0", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -3223,59 +3091,28 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" -[[package]] -name = "rustls-platform-verifier" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" -dependencies = [ - "core-foundation", - "core-foundation-sys", - "jni", - "log", - "once_cell", - "rustls 0.23.20", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki 0.102.8", - "security-framework", - "security-framework-sys", - "webpki-roots 0.26.7", - "winapi", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - [[package]] name = "rustls-webpki" version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "ring 0.17.8", + "ring", "rustls-pki-types", - "untrusted 0.9.0", + "untrusted", ] [[package]] -name = "rustversion" -version = "1.0.19" +name = "rusty-fork" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] [[package]] name = "ryu" @@ -3283,48 +3120,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scale-info" -version = "2.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" -dependencies = [ - "cfg-if", - "derive_more", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.94", -] - [[package]] name = "schannel" version = "0.1.27" @@ -3340,28 +3135,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "scrypt" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" -dependencies = [ - "hmac", - "pbkdf2 0.11.0", - "salsa20", - "sha2", -] - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - [[package]] name = "sealed" version = "0.6.0" @@ -3393,11 +3166,10 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.6.0", + "bitflags", "core-foundation", "core-foundation-sys", "libc", - "num-bigint", "security-framework-sys", ] @@ -3405,10 +3177,19 @@ dependencies = [ name = "security-framework-sys" version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" +checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "core-foundation-sys", - "libc", + "semver-parser", ] [[package]] @@ -3416,15 +3197,15 @@ name = "semver" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" -dependencies = [ - "serde", -] [[package]] -name = "send_wrapper" -version = "0.4.0" +name = "semver-parser" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] [[package]] name = "send_wrapper" @@ -3434,27 +3215,28 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] [[package]] -name = "serde_bytes" -version = "0.11.15" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ - "serde", + "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -3495,15 +3277,6 @@ dependencies = [ "syn 2.0.94", ] -[[package]] -name = "serde_spanned" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" -dependencies = [ - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3522,7 +3295,7 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ - "base64 0.22.1", + "base64", "chrono", "hex", "indexmap 1.9.3", @@ -3554,7 +3327,7 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -3565,17 +3338,17 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] -name = "sha3" -version = "0.10.8" +name = "sha3-asm" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" dependencies = [ - "digest", - "keccak", + "cc", + "cfg-if", ] [[package]] @@ -3599,8 +3372,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", - "rand_core", + "digest 0.10.7", + "rand_core 0.6.4", ] [[package]] @@ -3611,7 +3384,7 @@ checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" dependencies = [ "num-bigint", "num-traits", - "thiserror", + "thiserror 1.0.69", "time", ] @@ -3626,12 +3399,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - [[package]] name = "slab" version = "0.4.9" @@ -3657,42 +3424,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "soketto" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures", - "http 1.2.0", - "httparse", - "log", - "rand", - "sha1", -] - -[[package]] -name = "solang-parser" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" -dependencies = [ - "itertools", - "lalrpop", - "lalrpop-util", - "phf", - "thiserror", - "unicode-xid", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -3721,19 +3452,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", -] - [[package]] name = "strsim" version = "0.11.1" @@ -3742,23 +3460,22 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.3" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.4" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ "heck", "proc-macro2", "quote", - "rustversion", "syn 2.0.94", ] @@ -3768,26 +3485,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "svm-rs" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11297baafe5fa0c99d5722458eac6a5e25c01eb1b8e5cd137f54079093daa7a4" -dependencies = [ - "dirs", - "fs2", - "hex", - "once_cell", - "reqwest", - "semver", - "serde", - "serde_json", - "sha2", - "thiserror", - "url", - "zip", -] - [[package]] name = "syn" version = "1.0.109" @@ -3810,11 +3507,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn-solidity" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c837dc8852cb7074e46b444afb81783140dab12c58867b49fb3898fbafedf7ea" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.94", +] + [[package]] name = "sync_wrapper" -version = "0.1.2" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -3829,20 +3541,20 @@ dependencies = [ [[package]] name = "system-configuration" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "system-configuration-sys", ] [[package]] name = "system-configuration-sys" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" dependencies = [ "core-foundation-sys", "libc", @@ -3862,30 +3574,28 @@ checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", - "getrandom", + "getrandom 0.2.15", "once_cell", "rustix", "windows-sys 0.59.0", ] [[package]] -name = "term" -version = "0.7.0" +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "dirs-next", - "rustversion", - "winapi", + "thiserror-impl 1.0.69", ] [[package]] name = "thiserror" -version = "1.0.69" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.17", ] [[package]] @@ -3899,6 +3609,26 @@ dependencies = [ "syn 2.0.94", ] +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "time" version = "0.3.37" @@ -3949,21 +3679,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "tinyvec" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" version = "1.42.0" @@ -3994,12 +3709,12 @@ dependencies = [ ] [[package]] -name = "tokio-rustls" -version = "0.24.1" +name = "tokio-native-tls" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ - "rustls 0.21.12", + "native-tls", "tokio", ] @@ -4009,7 +3724,7 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls 0.23.20", + "rustls", "tokio", ] @@ -4027,17 +3742,18 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.20.1" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" dependencies = [ "futures-util", "log", - "rustls 0.21.12", + "rustls", + "rustls-pki-types", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls", "tungstenite", - "webpki-roots 0.25.4", + "webpki-roots", ] [[package]] @@ -4048,32 +3764,16 @@ checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", - "futures-io", "futures-sink", "pin-project-lite", "tokio", ] -[[package]] -name = "toml" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] [[package]] name = "toml_edit" @@ -4082,8 +3782,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap 2.7.0", - "serde", - "serde_spanned", "toml_datetime", "winnow", ] @@ -4103,6 +3801,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -4147,16 +3860,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "try-lock" version = "0.2.5" @@ -4165,21 +3868,21 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.20.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" dependencies = [ "byteorder", "bytes", "data-encoding", - "http 0.2.12", + "http", "httparse", "log", - "rand", - "rustls 0.21.12", + "rand 0.8.5", + "rustls", + "rustls-pki-types", "sha1", - "thiserror", - "url", + "thiserror 1.0.69", "utf-8", ] @@ -4189,6 +3892,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "uint" version = "0.9.5" @@ -4219,12 +3928,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" @@ -4267,14 +3970,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] -name = "uuid" -version = "0.8.2" +name = "valuable" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom", - "serde", -] +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" @@ -4283,13 +3988,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "walkdir" -version = "2.5.0" +name = "wait-timeout" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" dependencies = [ - "same-file", - "winapi-util", + "libc", ] [[package]] @@ -4307,6 +4011,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.99" @@ -4384,12 +4097,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "webpki-roots" version = "0.26.7" @@ -4400,42 +4107,47 @@ dependencies = [ ] [[package]] -name = "winapi" -version = "0.3.9" +name = "widestring" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] [[package]] -name = "winapi-util" -version = "0.1.9" +name = "windows-registry" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-sys 0.59.0", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows-result" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] [[package]] -name = "windows-core" -version = "0.52.0" +name = "windows-strings" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ + "windows-result", "windows-targets 0.52.6", ] @@ -4597,14 +4309,10 @@ dependencies = [ ] [[package]] -name = "winreg" -version = "0.50.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "write16" @@ -4629,9 +4337,9 @@ dependencies = [ "js-sys", "log", "pharos", - "rustc_version", - "send_wrapper 0.6.0", - "thiserror", + "rustc_version 0.4.1", + "send_wrapper", + "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -4646,12 +4354,6 @@ dependencies = [ "tap", ] -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - [[package]] name = "yoke" version = "0.7.5" @@ -4723,6 +4425,20 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.94", +] [[package]] name = "zerovec" @@ -4745,52 +4461,3 @@ dependencies = [ "quote", "syn 2.0.94", ] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2 0.11.0", - "sha1", - "time", - "zstd", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/Cargo.toml b/Cargo.toml index eb434ee..fe996f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,37 +1,29 @@ [package] name = "evm-indexer" -version = "1.5.1" +version = "2.0.0" license = "MIT" edition = "2021" repository = "https://github.com/eabz/evm-indexer" description = "Scalable SQL indexer for EVM compatible blockchains" [dependencies] -array-bytes = "9" +alloy = { version = "0.1", features = ["full", "node-bindings", "rpc-types", "json-rpc", "rpc-client"] } +alloy-rpc-types-trace = "0.1" clap = { version = "4", features = ["derive"] } -clickhouse = "0.13" -ethers = { version = "2", features = ["rustls"] } +clickhouse = { version = "0.14", features = ["native-tls"] } futures = "0.3" hex = "0.4" -jsonrpsee = { version = "0.24", features = ["macros", "server"] } -jsonrpsee-http-client = "0.24" -jsonrpsee-ws-client = "0.24" log = "0.4" -primitive-types = "0.12" rand = "0.8" -serde = "1" -serde_bytes = "0.11" +reqwest = { version = "0.12", features = ["json"] } +serde = { version = "1", features = ["derive"] } serde_json = "1" serde_repr = "0.1" serde_with = "3" +simple_logger = { version = "5", default-features = false, features = ["colors"] } tokio = { version = "1", features = ["full"] } url = "2" -[dependencies.simple_logger] -version = "5" -default-features = false -features = ["colors"] - [[bin]] path = "bin/indexer.rs" name = "indexer" diff --git a/README.md b/README.md index 33c4e93..2738611 100644 --- a/README.md +++ b/README.md @@ -2,62 +2,155 @@ EVM Blockchain Indexer

-Scalable SQL indexer for EVM-compatible blockchains +High-performance SQL indexer for EVM-compatible blockchains

[![Docker Image Size](https://badgen.net/docker/size/0xeabz/evm-indexer/main?icon=docker&label=image%20size)](https://hub.docker.com/r/0xeabz/evm-indexer) ![build](https://github.com/eabz/evm-indexer/actions/workflows/build.yml/badge.svg) -An indexer is a program that fetches and stores blockchain data for later analysis. +A production-ready indexer that fetches and stores blockchain data for later analysis. Optimized for performance with support for parallel block processing, dynamic RPC capability detection, and efficient memory usage. -This indexer is specifically created to parse known data for EVM-compatible chains. +## Features -It stores all the blockchain primitives (blocks, transactions, receipts, logs, traces, withdrawals) and some other useful information (contracts created, erc20 transfers, erc721 transfers, erc1155 transfers) +- ✅ **Complete blockchain primitives**: blocks, transactions, receipts, logs, traces, withdrawals +- ✅ **Token transfers**: ERC20, ERC721, ERC1155 +- ✅ **DEX trades**: Uniswap V2, V3 swap events +- ✅ **Contract tracking**: Automatically indexes deployed contracts +- ✅ **Parallel processing**: Configurable batch size for optimal throughput +- ✅ **Smart RPC usage**: Auto-detects `eth_getBlockReceipts` support +- ✅ **Memory efficient**: Arc-based storage, pre-allocated HashMaps +- ✅ **Production ready**: Comprehensive logging, error handling, Docker support ## Requirements -- [Rust](https://www.rust-lang.org/tools/install) -- [ClickHouse](https://clickhouse.com/) +- [Rust](https://www.rust-lang.org/tools/install) 1.70+ +- [ClickHouse](https://clickhouse.com/) 23.0+ +## Quick Start -### Local +### Using Docker Compose (Recommended) -1. Clone the repository - -``` +1. Clone the repository: +```bash git clone https://github.com/eabz/evm-indexer && cd evm-indexer ``` -2. Build the program - +2. Start the services: +```bash +docker-compose up -d ``` -cargo build --release -``` - -### Docker -1. Clone the repository +This will start: +- ClickHouse database on ports 8123 (HTTP) and 9000 (native) +- Indexer configured for Ethereum mainnet +3. Monitor logs: +```bash +docker-compose logs -f indexer ``` + +### Local Development + +1. Clone the repository: +```bash git clone https://github.com/eabz/evm-indexer && cd evm-indexer ``` -2. Build the image and tag it as `indexer` +2. Build the program: +```bash +cargo build --release +``` +3. Run the indexer: +```bash +./target/release/indexer \ + --chain 1 \ + --database clickhouse://user:password@localhost:8123/indexer \ + --rpcs https://eth.llamarpc.com \ + --start-block 0 \ + --batch-size 100 ``` -docker build . -t indexer + +## Configuration + +### CLI Flags + +| Flag | Default | Description | +|------|---------|-------------| +| `--chain` | `1` | Chain ID to index (1=Ethereum, 56=BSC, 137=Polygon, etc.) | +| `--database` | *required* | ClickHouse connection string: `clickhouse://user:pass@host:port/db` | +| `--rpcs` | *required* | Comma-separated list of RPC endpoints | +| `--start-block` | `0` | Block number to start syncing from | +| `--end-block` | `0` | Last block to sync (0 = continuous sync) | +| `--batch-size` | `200` | Number of blocks to fetch in parallel | +| `--ws` | `""` | WebSocket endpoint for real-time block updates | +| `--traces` | `true` | Fetch transaction traces (requires archive node) | +| `--fetch-uncles` | `false` | Fetch uncle blocks (adds 5-10% RPC calls) | +| `--new-blocks-only` | `false` | Only index new blocks (skip historical sync) | +| `--debug` | `false` | Enable debug logging | + +### Environment Variables + +Create a `.env` file (see `.env.example`): +```bash +# ClickHouse Configuration +CLICKHOUSE_DB=indexer +CLICKHOUSE_USER=indexer +CLICKHOUSE_PASSWORD=indexer + +# Indexer Configuration +CHAIN_ID=1 +START_BLOCK=0 +BATCH_SIZE=10 +RPC_URL=https://eth.llamarpc.com +DEBUG=true +FETCH_UNCLES=false +TRACES=true ``` -## Program flags - -| Flag | Default | Purpose | -| --------------- | :-----: | ------------------------------------------------------ | -| `--debug` | false | Start log with debug. | -| `--chain` | 1 | Number identifying the chain id to sync. | -| `--start-block` | 0 | Block to start syncing. | -| `--end-block` | 0 | Last block to sync (0 to sync all the blocks). | -| `--batch-size` | 200 | Amount of blocks to fetch in parallel. | -| `--rpcs` | `empty` | Comma separated list of rpcs to use to fetch blocks. | -| `--database` | `empty` | Clickhouse database string with username and password. | -| `--ws` | `empty` | Url of the websocket endpoint to fetch new blocks. | -| `--traces` | true | Fetch blockchain traces. | +## Database Schema + +The indexer creates the following tables in ClickHouse: + +- `blocks` - Block headers and metadata +- `transactions` - Transaction data with gas info +- `logs` - Event logs emitted by contracts +- `traces` - Internal transaction traces +- `contracts` - Deployed contract addresses +- `withdrawals` - Validator withdrawals (post-merge) +- `erc20_transfers` - ERC20 token transfers +- `erc721_transfers` - NFT transfers +- `erc1155_transfers` - Multi-token transfers +- `dex_trades` - DEX trades + +See `migrations/create_tables.sql` for full schema. + +## Performance Tuning + +### Batch Size +- **Small batches (10-50)**: Lower memory, slower throughput +- **Medium batches (100-200)**: Balanced (recommended) +- **Large batches (500+)**: Higher memory, faster throughput + +### RPC Endpoints +- Use multiple RPCs for better reliability +- Archive nodes required for traces +- `eth_getBlockReceipts` support = 2x faster + +### ClickHouse +- Use SSD storage for better performance +- Increase `max_insert_block_size` for large batches +- Enable compression for storage savings + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +## License + +MIT License - see LICENSE file for details + +## Support + +- GitHub Issues: [Report bugs](https://github.com/eabz/evm-indexer/issues) +- Discussions: [Ask questions](https://github.com/eabz/evm-indexer/discussions) diff --git a/bin/indexer.rs b/bin/indexer.rs index ee55edc..900ed44 100644 --- a/bin/indexer.rs +++ b/bin/indexer.rs @@ -23,18 +23,11 @@ async fn main() { info!("Starting EVM Indexer."); - info!("Syncing {}.", config.chain.name); + info!("Syncing chain id {}.", config.chain_id); let rpc = Rpc::new(&config).await; - let db = Database::new( - config.db_host.clone(), - config.db_username.clone(), - config.db_password.clone(), - config.db_name.clone(), - config.chain.clone(), - ) - .await; + let db = Database::new(&config.database_url, config.chain_id).await; if config.ws_url.is_some() && config.end_block == 0 || config.end_block == -1 @@ -94,7 +87,7 @@ async fn sync_chain(rpc: &Rpc, db: &Database, config: &Config) { let mut work = vec![]; for block_number in missing_blocks_chunk { - work.push(rpc.fetch_block(block_number, &config.chain)) + work.push(rpc.fetch_block(block_number)) } let results = join_all(work).await; @@ -109,6 +102,7 @@ async fn sync_chain(rpc: &Rpc, db: &Database, config: &Config) { erc20_transfers: Vec::new(), erc721_transfers: Vec::new(), erc1155_transfers: Vec::new(), + dex_trades: Vec::new(), }; for result in results { @@ -123,6 +117,7 @@ async fn sync_chain(rpc: &Rpc, db: &Database, config: &Config) { mut erc20_transfers, mut erc721_transfers, mut erc1155_transfers, + mut dex_trades, )) => { fetched_data.blocks.append(&mut blocks); fetched_data.transactions.append(&mut transactions); @@ -139,6 +134,7 @@ async fn sync_chain(rpc: &Rpc, db: &Database, config: &Config) { fetched_data .erc1155_transfers .append(&mut erc1155_transfers); + fetched_data.dex_trades.append(&mut dex_trades); } None => continue, } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..222a20b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,52 @@ +services: + clickhouse: + image: clickhouse/clickhouse-server:latest + container_name: evm-indexer-clickhouse + ports: + - "8123:8123" + - "9000:9000" + volumes: + - clickhouse_data:/var/lib/clickhouse + - ./migrations:/docker-entrypoint-initdb.d:ro + environment: + CLICKHOUSE_DB: indexer + CLICKHOUSE_USER: indexer + CLICKHOUSE_PASSWORD: indexer + CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1 + healthcheck: + test: ["CMD", "clickhouse-client", "--query", "SELECT 1"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - indexer-network + + indexer: + build: + context: . + dockerfile: Dockerfile + container_name: evm-indexer + depends_on: + clickhouse: + condition: service_healthy + environment: + - RUST_LOG=info + command: > + indexer + --chain 1 + --database clickhouse://indexer:indexer@clickhouse:8123/indexer + --rpcs https://0xrpc.io/eth + --ws wss://0xrpc.io/eth + --start-block 15000000 + --batch-size 10 + networks: + - indexer-network + restart: unless-stopped + +volumes: + clickhouse_data: + driver: local + +networks: + indexer-network: + driver: bridge diff --git a/migrations/create_tables.sql b/migrations/create_tables.sql index d7a8b1c..df68915 100644 --- a/migrations/create_tables.sql +++ b/migrations/create_tables.sql @@ -1,9 +1,9 @@ CREATE DATABASE IF NOT EXISTS indexer; -CREATE TABLE indexer.blocks ( +CREATE TABLE IF NOT EXISTS indexer.blocks ( base_fee_per_gas Nullable(UInt64), chain UInt64, - difficulty UInt256, + difficulty String, extra_data String CODEC(ZSTD(9)), gas_limit UInt32, gas_used UInt32, @@ -13,14 +13,14 @@ CREATE TABLE indexer.blocks ( miner String, mix_hash Nullable(String), nonce String, - number UInt32, + number UInt32 CODEC(Delta, ZSTD), parent_hash String, receipts_root String, sha3_uncles String, size UInt32, state_root String, - timestamp DateTime, - total_difficulty Nullable(UInt256), + timestamp DateTime CODEC(Delta, ZSTD), + total_difficulty Nullable(String), transactions UInt16, transactions_root String, uncles Array(String), @@ -28,30 +28,30 @@ CREATE TABLE indexer.blocks ( ) ENGINE = ReplacingMergeTree() PARTITION BY toYYYYMM(timestamp) -ORDER BY (hash, miner, chain, timestamp, number) +ORDER BY (chain, number, hash) SETTINGS index_granularity = 8192; -CREATE TABLE indexer.contracts ( - block_number UInt32, +CREATE TABLE IF NOT EXISTS indexer.contracts ( + block_number UInt32 CODEC(Delta, ZSTD), chain UInt64, contract_address String, creator String, transaction_hash String ) ENGINE = ReplacingMergeTree() -ORDER BY (contract_address, transaction_hash, creator, chain) +ORDER BY (chain, block_number, contract_address) SETTINGS index_granularity = 8192; -CREATE TABLE indexer.logs ( +CREATE TABLE IF NOT EXISTS indexer.logs ( address String, - block_number UInt32, + block_number UInt32 CODEC(Delta, ZSTD), chain UInt64, data String CODEC(ZSTD(9)), - log_index UInt16, + log_index UInt16 CODEC(Delta, ZSTD), log_type Nullable(String), removed Boolean, - timestamp DateTime, - topic0 String, + timestamp DateTime CODEC(Delta, ZSTD), + topic0 Nullable(String), topic1 Nullable(String), topic2 Nullable(String), topic3 Nullable(String), @@ -60,19 +60,19 @@ CREATE TABLE indexer.logs ( ) ENGINE = ReplacingMergeTree() PARTITION BY toYYYYMM(timestamp) -ORDER BY (transaction_hash, address, chain, topic0, log_index, timestamp) +ORDER BY (chain, block_number, log_index, transaction_hash) SETTINGS index_granularity = 8192; -CREATE TABLE indexer.erc20_transfers ( +CREATE TABLE IF NOT EXISTS indexer.erc20_transfers ( address String, - amount UInt256, - block_number UInt32, + amount String, + block_number UInt32 CODEC(Delta, ZSTD), chain UInt64, from String, - log_index UInt16, + log_index UInt16 CODEC(Delta, ZSTD), log_type Nullable(String), removed Boolean, - timestamp DateTime, + timestamp DateTime CODEC(Delta, ZSTD), to String, token_address String, transaction_hash String, @@ -80,19 +80,19 @@ CREATE TABLE indexer.erc20_transfers ( ) ENGINE = ReplacingMergeTree() PARTITION BY toYYYYMM(timestamp) -ORDER BY (transaction_hash, address, chain, log_index, timestamp) +ORDER BY (chain, block_number, log_index, transaction_hash) SETTINGS index_granularity = 8192; -CREATE TABLE indexer.erc721_transfers ( +CREATE TABLE IF NOT EXISTS indexer.erc721_transfers ( address String, - block_number UInt32, + block_number UInt32 CODEC(Delta, ZSTD), chain UInt64, from String, - id UInt256, - log_index UInt16, + id String, + log_index UInt16 CODEC(Delta, ZSTD), log_type Nullable(String), removed Boolean, - timestamp DateTime, + timestamp DateTime CODEC(Delta, ZSTD), to String, token_address String, transaction_hash String, @@ -100,21 +100,21 @@ CREATE TABLE indexer.erc721_transfers ( ) ENGINE = ReplacingMergeTree() PARTITION BY toYYYYMM(timestamp) -ORDER BY (transaction_hash, address, chain, log_index, timestamp) +ORDER BY (chain, block_number, log_index, transaction_hash) SETTINGS index_granularity = 8192; -CREATE TABLE indexer.erc1155_transfers ( +CREATE TABLE IF NOT EXISTS indexer.erc1155_transfers ( address String, - amounts Array(UInt256), - block_number UInt32, + amounts Array(String), + block_number UInt32 CODEC(Delta, ZSTD), chain UInt64, from String, - ids Array(UInt256), - log_index UInt16, + ids Array(String), + log_index UInt16 CODEC(Delta, ZSTD), log_type Nullable(String), operator String, removed Boolean, - timestamp DateTime, + timestamp DateTime CODEC(Delta, ZSTD), to String, token_address String, transaction_hash String, @@ -122,18 +122,18 @@ CREATE TABLE indexer.erc1155_transfers ( ) ENGINE = ReplacingMergeTree() PARTITION BY toYYYYMM(timestamp) -ORDER BY (transaction_hash, address, chain, log_index, timestamp) +ORDER BY (chain, block_number, log_index, transaction_hash) SETTINGS index_granularity = 8192; -CREATE TABLE indexer.traces ( - action_type Enum8('call' = 1, 'create' = 2, 'suicide' = 3, 'reward' = 4), +CREATE TABLE IF NOT EXISTS indexer.traces ( + action_type String, address Nullable(String), author Nullable(String), - balance Nullable(UInt256), + balance Nullable(String), block_hash String, - block_number UInt32, - call_type Nullable(Enum8('none' = 0, 'call' = 1, 'callcode' = 2, 'delegatecall' = 3, 'staticcall' = 4)), + block_number UInt32 CODEC(Delta, ZSTD), + call_type Nullable(String), chain UInt64, code Nullable(String), error Nullable(String), @@ -144,59 +144,79 @@ CREATE TABLE indexer.traces ( input Nullable(String) CODEC(ZSTD(9)), output Nullable(String) CODEC(ZSTD(9)), refund_address Nullable(String), - reward_type Nullable(Enum8('block' = 1, 'uncle' = 2, 'emptyStep' = 3, 'external' = 4)), + reward_type Nullable(String), subtraces UInt16, to Nullable(String), trace_address Array(UInt16), transaction_hash Nullable(String), transaction_position Nullable(UInt16), - value Nullable(UInt256) + value Nullable(String) ) ENGINE = ReplacingMergeTree() -ORDER BY (block_hash, trace_address) +ORDER BY (chain, block_number) SETTINGS index_granularity = 8192; -CREATE TABLE indexer.transactions ( +CREATE TABLE IF NOT EXISTS indexer.transactions ( access_list Array(Tuple(String, Array(String))), base_fee_per_gas Nullable(UInt64), block_hash String, - block_number UInt32, + block_number UInt32 CODEC(Delta, ZSTD), chain UInt64, contract_created Nullable(String), cumulative_gas_used Nullable(UInt32), - effective_gas_price Nullable(UInt256), + effective_gas_price Nullable(String), from String, gas UInt32, - gas_price Nullable(UInt256), + gas_price Nullable(String), gas_used Nullable(UInt32), hash String, input String CODEC(ZSTD(9)), - max_fee_per_gas Nullable(UInt256), - max_priority_fee_per_gas Nullable(UInt256), + max_fee_per_gas Nullable(String), + max_priority_fee_per_gas Nullable(String), method String, nonce UInt32, - status Nullable(Enum8('unknown' = 0, 'failure' = 1, 'success' = 2)), - timestamp DateTime, + status Nullable(String), + timestamp DateTime CODEC(Delta, ZSTD), to String, transaction_index UInt16, - transaction_type Enum8('legacy' = 0, 'access_list' = 1, 'eip_1559' = 2), - value UInt256 + transaction_type String, + value String ) ENGINE = ReplacingMergeTree() PARTITION BY toYYYYMM(timestamp) -ORDER BY (hash, from, to, timestamp, chain, method) +ORDER BY (chain, block_number, transaction_index, hash) SETTINGS index_granularity = 8192; -CREATE TABLE indexer.withdrawals ( +CREATE TABLE IF NOT EXISTS indexer.withdrawals ( address String, - amount UInt256, - block_number UInt32, + amount String, + block_number UInt32 CODEC(Delta, ZSTD), chain UInt64, - timestamp DateTime, - validator_index UInt32, - withdrawal_index UInt32 + timestamp DateTime CODEC(Delta, ZSTD), + validator_index UInt64, + withdrawal_index UInt64 ) ENGINE = ReplacingMergeTree() PARTITION BY toYYYYMM(timestamp) -ORDER BY (address, block_number, chain, timestamp, validator_index) +ORDER BY (chain, block_number, withdrawal_index) +SETTINGS index_granularity = 8192; + +CREATE TABLE IF NOT EXISTS indexer.dex_trades ( + block_number UInt32 CODEC(Delta, ZSTD), + chain UInt64, + transaction_hash String, + log_index UInt16 CODEC(Delta, ZSTD), + pool_address String, + sender String, + recipient String, + amount0_in String, + amount1_in String, + amount0_out String, + amount1_out String, + dex_name String, + timestamp DateTime CODEC(Delta, ZSTD) +) +ENGINE = ReplacingMergeTree() +PARTITION BY toYYYYMM(timestamp) +ORDER BY (chain, pool_address, block_number, log_index) SETTINGS index_granularity = 8192; \ No newline at end of file diff --git a/migrations/create_views.sql b/migrations/create_views.sql deleted file mode 100644 index 7c9744a..0000000 --- a/migrations/create_views.sql +++ /dev/null @@ -1,46 +0,0 @@ -ALTER TABLE contracts ADD PROJECTION contracts_count_by_chain (SELECT count(*) as contracts, chain GROUP BY chain); - -ALTER TABLE contracts - MATERIALIZE PROJECTION contracts_count_by_chain SETTINGS mutations_sync = 1; - -ALTER TABLE logs ADD PROJECTION logs_count_by_chain (SELECT count(*) as logs, chain GROUP BY chain); - -ALTER TABLE logs - MATERIALIZE PROJECTION logs_count_by_chain SETTINGS mutations_sync = 1; - -ALTER TABLE traces ADD PROJECTION traces_count_by_chain (SELECT count(*) as traces, chain GROUP BY chain); - -ALTER TABLE traces - MATERIALIZE PROJECTION traces_count_by_chain SETTINGS mutations_sync = 1; - -ALTER TABLE transactions ADD PROJECTION transactions_count_by_chain (SELECT count(*) as transactions, chain GROUP BY chain); - -ALTER TABLE transactions - MATERIALIZE PROJECTION transactions_count_by_chain SETTINGS mutations_sync = 1; - -ALTER TABLE withdrawals ADD PROJECTION withdrawals_count_by_chain (SELECT count(*) as withdrawals, chain GROUP BY chain); - -ALTER TABLE withdrawals - MATERIALIZE PROJECTION withdrawals_count_by_chain SETTINGS mutations_sync = 1; - -ALTER TABLE erc20_transfers ADD PROJECTION erc20_transfers_count_by_chain (SELECT count(*) as erc20_transfers, chain GROUP BY chain); - -ALTER TABLE erc20_transfers - MATERIALIZE PROJECTION erc20_transfers_count_by_chain SETTINGS mutations_sync = 1; - -ALTER TABLE erc721_transfers ADD PROJECTION erc721_transfers_count_by_chain (SELECT count(*) as erc721_transfers, chain GROUP BY chain); - -ALTER TABLE erc721_transfers - MATERIALIZE PROJECTION erc721_transfers_count_by_chain SETTINGS mutations_sync = 1; - -ALTER TABLE erc1155_transfers ADD PROJECTION erc1155_transfers_count_by_chain (SELECT count(*) as erc1155_transfers, chain GROUP BY chain); - -ALTER TABLE erc1155_transfers - MATERIALIZE PROJECTION erc1155_transfers_count_by_chain SETTINGS mutations_sync = 1; - -ALTER TABLE dex_trades ADD PROJECTION dex_trades_count_by_chain (SELECT count(*) as dex_trades, chain GROUP BY chain); - -ALTER TABLE dex_trades - MATERIALIZE PROJECTION dex_trades_count_by_chain SETTINGS mutations_sync = 1; - - diff --git a/src/chains/mod.rs b/src/chains/mod.rs deleted file mode 100644 index 8976e2f..0000000 --- a/src/chains/mod.rs +++ /dev/null @@ -1,65 +0,0 @@ -use std::collections::HashMap; - -use primitive_types::U256; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -struct BalanceAllocation { - balance: U256, -} - -#[derive(Debug, Clone)] -pub struct Chain { - pub id: u64, - pub name: &'static str, - pub supports_blocks_receipts: bool, - pub supports_trace_block: bool, -} - -pub const ETHEREUM: Chain = Chain { - id: 1, - name: "ethereum", - supports_blocks_receipts: true, - supports_trace_block: true, -}; - -pub const POLYGON: Chain = Chain { - id: 137, - name: "polygon", - supports_blocks_receipts: true, - supports_trace_block: true, -}; - -pub const BSC: Chain = Chain { - id: 56, - name: "bsc", - supports_blocks_receipts: true, - supports_trace_block: true, -}; - -pub const MONAD_DEVNET: Chain = Chain { - id: 41454, - name: "DMON", - supports_blocks_receipts: false, - supports_trace_block: false, -}; - -pub static CHAINS: [Chain; 4] = [ETHEREUM, POLYGON, BSC, MONAD_DEVNET]; - -pub fn get_chains() -> HashMap { - let mut chains: HashMap = HashMap::new(); - - for chain in CHAINS.iter() { - chains.insert(chain.id, chain.to_owned()); - } - - chains -} - -pub fn get_chain(chain: u64) -> Chain { - let chains = get_chains(); - - let selected_chain = chains.get(&chain).expect("chain not found."); - - selected_chain.to_owned() -} diff --git a/src/configs/mod.rs b/src/configs/mod.rs index c578066..f42b4b3 100644 --- a/src/configs/mod.rs +++ b/src/configs/mod.rs @@ -1,6 +1,4 @@ -use crate::chains::{get_chain, Chain}; use clap::Parser; -use url::Url; #[derive(Parser, Debug)] #[command( @@ -54,16 +52,15 @@ pub struct IndexerArgs { default_value_t = true )] pub traces: bool, + #[arg(long, help = "Fetch uncle blocks.", default_value_t = false)] + pub fetch_uncles: bool, } #[derive(Debug, Clone)] pub struct Config { pub batch_size: usize, - pub chain: Chain, - pub db_host: String, - pub db_name: String, - pub db_password: String, - pub db_username: String, + pub chain_id: u64, + pub database_url: String, pub debug: bool, pub end_block: i64, pub new_blocks_only: bool, @@ -71,6 +68,7 @@ pub struct Config { pub start_block: u32, pub ws_url: Option, pub traces: bool, + pub fetch_uncles: bool, } impl Default for Config { @@ -83,37 +81,16 @@ impl Config { pub fn new() -> Self { let args = IndexerArgs::parse(); - let chain = get_chain(args.chain as u64); - let rpcs: Vec = args.rpcs.split(',').map(|rpc| rpc.to_string()).collect(); let ws_url: Option = if args.ws.is_empty() { None } else { Some(args.ws) }; - let url = Url::parse(&args.database).expect("unable to parse database url expected: scheme://username:password@host/database"); - - let username = url.username(); - - let password = - url.password().expect("no password provided for database"); - - let db_host = - url.host().expect("no host provided for database").to_string(); - - let url_paths = - url.path_segments().map(|c| c.collect::>()).unwrap(); - - let db_name = - url_paths.first().expect("no database name provided on path"); - Self { batch_size: args.batch_size, - chain, - db_host: format!("{}://{}", url.scheme(), db_host), - db_name: db_name.to_string(), - db_password: password.to_string(), - db_username: username.to_string(), + chain_id: args.chain as u64, + database_url: args.database, debug: args.debug, end_block: args.end_block, new_blocks_only: args.new_blocks_only, @@ -121,6 +98,7 @@ impl Config { start_block: args.start_block, ws_url, traces: args.traces, + fetch_uncles: args.fetch_uncles, } } } diff --git a/src/db/mod.rs b/src/db/mod.rs index 5b19b33..0db1087 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,13 +1,12 @@ pub mod models; -use crate::chains::Chain; use clickhouse::{Client, Row}; use futures::future::join_all; use log::{error, info}; use models::{ - block::DatabaseBlock, contract::DatabaseContract, log::DatabaseLog, - trace::DatabaseTrace, transaction::DatabaseTransaction, - withdrawal::DatabaseWithdrawal, + block::DatabaseBlock, contract::DatabaseContract, + dex_trade::DatabaseDexTrade, log::DatabaseLog, trace::DatabaseTrace, + transaction::DatabaseTransaction, withdrawal::DatabaseWithdrawal, }; use serde::Serialize; use std::collections::HashSet; @@ -28,11 +27,12 @@ pub struct BlockFetchedData { pub erc20_transfers: Vec, pub erc721_transfers: Vec, pub erc1155_transfers: Vec, + pub dex_trades: Vec, } #[derive(Clone)] pub struct Database { - pub chain: Chain, + pub chain_id: u64, pub db: Client, } @@ -67,28 +67,59 @@ impl DatabaseTables { } impl Database { - pub async fn new( - db_host: String, - db_username: String, - db_password: String, - db_name: String, - chain: Chain, - ) -> Self { - info!("Starting EVM database service"); - - let db = Client::default() - .with_url(db_host) - .with_user(db_username) - .with_password(db_password) - .with_database(db_name); - - Self { chain, db } + pub async fn new(database_url: &str, chain_id: u64) -> Self { + info!("Connecting to database: {}", database_url); + + // Parse the database URL to extract components + let url = url::Url::parse(database_url) + .expect("Failed to parse database URL. Expected format: clickhouse://user:password@host:port/database"); + + let host = url.host_str().expect("No host in database URL"); + let port = url.port().unwrap_or(9000); + let username = url.username(); + let password = url.password().unwrap_or(""); + let database = url.path().trim_start_matches('/'); + + let db = clickhouse::Client::default() + .with_url(format!("{}://{}:{}", url.scheme(), host, port)) + .with_user(username) + .with_password(password) + .with_database(database); + + // Retry connection test up to 10 times with exponential backoff + let mut retries = 0; + let max_retries = 10; + + loop { + match db.query("SELECT 1").fetch_one::().await { + Ok(_) => { + info!("Successfully connected to ClickHouse database '{}'", database); + break; + } + Err(e) => { + retries += 1; + if retries >= max_retries { + error!("Failed to connect to database after {} attempts: {}", max_retries, e); + panic!("Could not connect to ClickHouse. Please check your database configuration and ensure ClickHouse is running."); + } + + let wait_time = std::time::Duration::from_secs( + 2_u64.pow(retries.min(5)), + ); + log::warn!("Database connection attempt {}/{} failed: {}. Retrying in {:?}...", + retries, max_retries, e, wait_time); + tokio::time::sleep(wait_time).await; + } + } + } + + Self { chain_id, db } } pub async fn get_indexed_blocks(&self) -> HashSet { let query = format!( "SELECT number FROM blocks WHERE chain = {} AND is_uncle = false", - self.chain.id + self.chain_id ); let tokens = (self.db.query(&query).fetch_all::().await) @@ -100,134 +131,117 @@ impl Database { } pub async fn store_data(&self, data: &BlockFetchedData) { + use std::sync::Arc; + let mut stores = vec![]; if !data.contracts.is_empty() { - let work = tokio::spawn({ - let contracts = data.contracts.clone(); - let db = self.clone(); - async move { - db.store_items( - &contracts, - DatabaseTables::Contracts.as_str(), - ) - .await - } + let contracts = Arc::new(data.contracts.clone()); + let db = self.clone(); + let work = tokio::spawn(async move { + db.store_items( + &contracts, + DatabaseTables::Contracts.as_str(), + ) + .await }); - stores.push(work); } if !data.logs.is_empty() { - let work = tokio::spawn({ - let logs = data.logs.clone(); - let db = self.clone(); - async move { - db.store_items(&logs, DatabaseTables::Logs.as_str()) - .await - } + let logs = Arc::new(data.logs.clone()); + let db = self.clone(); + let work = tokio::spawn(async move { + db.store_items(&logs, DatabaseTables::Logs.as_str()).await }); - stores.push(work); } if !data.traces.is_empty() { - let work = tokio::spawn({ - let traces = data.traces.clone(); - let db = self.clone(); - async move { - db.store_items( - &traces, - DatabaseTables::Traces.as_str(), - ) + let traces = Arc::new(data.traces.clone()); + let db = self.clone(); + let work = tokio::spawn(async move { + db.store_items(&traces, DatabaseTables::Traces.as_str()) .await - } }); - stores.push(work); } if !data.transactions.is_empty() { - let work = tokio::spawn({ - let transactions = data.transactions.clone(); - let db = self.clone(); - async move { - db.store_items( - &transactions, - DatabaseTables::Transactions.as_str(), - ) - .await - } + let transactions = Arc::new(data.transactions.clone()); + let db = self.clone(); + let work = tokio::spawn(async move { + db.store_items( + &transactions, + DatabaseTables::Transactions.as_str(), + ) + .await }); - stores.push(work); } if !data.withdrawals.is_empty() { - let work = tokio::spawn({ - let withdrawals: Vec = - data.withdrawals.clone(); - let db = self.clone(); - async move { - db.store_items( - &withdrawals, - DatabaseTables::Withdrawals.as_str(), - ) - .await - } + let withdrawals = Arc::new(data.withdrawals.clone()); + let db = self.clone(); + let work = tokio::spawn(async move { + db.store_items( + &withdrawals, + DatabaseTables::Withdrawals.as_str(), + ) + .await }); - stores.push(work); } if !data.erc20_transfers.is_empty() { - let work = tokio::spawn({ - let transfers: Vec = - data.erc20_transfers.clone(); - let db = self.clone(); - async move { - db.store_items( - &transfers, - DatabaseTables::Erc20Transfers.as_str(), - ) - .await - } + let transfers = Arc::new(data.erc20_transfers.clone()); + let db = self.clone(); + let work = tokio::spawn(async move { + db.store_items( + &transfers, + DatabaseTables::Erc20Transfers.as_str(), + ) + .await }); - stores.push(work); } if !data.erc721_transfers.is_empty() { - let work = tokio::spawn({ - let transfers: Vec = - data.erc721_transfers.clone(); - let db = self.clone(); - async move { - db.store_items( - &transfers, - DatabaseTables::Erc721Transfers.as_str(), - ) - .await - } + let transfers = Arc::new(data.erc721_transfers.clone()); + let db = self.clone(); + let work = tokio::spawn(async move { + db.store_items( + &transfers, + DatabaseTables::Erc721Transfers.as_str(), + ) + .await }); - stores.push(work); } if !data.erc1155_transfers.is_empty() { - let work = tokio::spawn({ - let transfers: Vec = - data.erc1155_transfers.clone(); - let db = self.clone(); - async move { - db.store_items( - &transfers, - DatabaseTables::Erc1155Transfers.as_str(), - ) - .await - } + let transfers = Arc::new(data.erc1155_transfers.clone()); + let db = self.clone(); + let work = tokio::spawn(async move { + db.store_items( + &transfers, + DatabaseTables::Erc1155Transfers.as_str(), + ) + .await }); + stores.push(work); + } + if !data.dex_trades.is_empty() { + let dex_trades = Arc::new(data.dex_trades.clone()); + let db = self.clone(); + let work = tokio::spawn(async move { + db.store_items( + &dex_trades, + DatabaseTables::DexTrades.as_str(), + ) + .await + }); stores.push(work); } @@ -249,7 +263,7 @@ impl Database { } info!( - "Inserted: contracts ({}) logs ({}) traces ({}) transactions ({}) withdrawals ({}) erc20 ({}) erc721 ({}) erc1155 ({}) in ({}) blocks.", + "Inserted: contracts ({}) logs ({}) traces ({}) transactions ({}) withdrawals ({}) erc20 ({}) erc721 ({}) erc1155 ({}) dex_trades ({}) in ({}) blocks.", data.contracts.len(), data.logs.len(), data.traces.len(), @@ -258,16 +272,23 @@ impl Database { data.erc20_transfers.len(), data.erc721_transfers.len(), data.erc1155_transfers.len(), + data.dex_trades.len(), data.blocks.len() ); } pub async fn store_items(&self, items: &Vec, table: &str) where - T: Row + Serialize, + T: Serialize, + for<'a> T: Row = T>, { - let mut inserter = self.db.insert(table).unwrap(); + if items.is_empty() { + return; + } + + let mut inserter = self.db.insert::(table).await.unwrap(); + // Write all items - ClickHouse client handles batching internally for item in items { inserter.write(item).await.unwrap(); } diff --git a/src/db/models/block.rs b/src/db/models/block.rs index e8b4117..0877c73 100644 --- a/src/db/models/block.rs +++ b/src/db/models/block.rs @@ -1,13 +1,10 @@ +use alloy::primitives::{Address, Bloom, Bytes, B256, B64, U256}; +use alloy::rpc::types::Block; use clickhouse::Row; -use ethers::types::Block; -use primitive_types::U256; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use crate::utils::format::{ - format_address, format_bytes, format_bytes_slice, format_hash, - format_nonce, SerU256, -}; +use crate::utils::format::SerU256; #[serde_as] #[derive(Debug, Clone, Row, Serialize, Deserialize)] @@ -16,28 +13,28 @@ pub struct DatabaseBlock { pub chain: u64, #[serde_as(as = "SerU256")] pub difficulty: U256, - pub extra_data: String, + pub extra_data: Bytes, pub gas_limit: u32, pub gas_used: u32, - pub hash: String, + pub hash: B256, pub is_uncle: bool, - pub logs_bloom: String, - pub miner: String, - pub mix_hash: Option, - pub nonce: String, + pub logs_bloom: Bloom, + pub miner: Address, + pub mix_hash: Option, + pub nonce: B64, pub number: u32, - pub parent_hash: String, - pub receipts_root: String, - pub sha3_uncles: String, + pub parent_hash: B256, + pub receipts_root: B256, + pub sha3_uncles: B256, pub size: u32, - pub state_root: String, + pub state_root: B256, pub timestamp: u32, #[serde_as(as = "Option")] pub total_difficulty: Option, pub transactions: u16, - pub transactions_root: String, - pub uncles: Vec, - pub withdrawals_root: Option, + pub transactions_root: B256, + pub uncles: Vec, + pub withdrawals_root: Option, } impl DatabaseBlock { @@ -46,45 +43,34 @@ impl DatabaseBlock { chain: u64, is_uncle: bool, ) -> Self { - let withdrawals_root: Option = - block.withdrawals_root.map(format_hash); - - let base_fee_per_gas: Option = block - .base_fee_per_gas - .map(|base_fee_per_gas| base_fee_per_gas.as_u64()); - Self { - base_fee_per_gas, + base_fee_per_gas: block + .header + .base_fee_per_gas + .map(|v| v.try_into().unwrap()), chain, - difficulty: block.difficulty, - extra_data: format_bytes(&block.extra_data), - gas_limit: block.gas_limit.as_usize() as u32, - gas_used: block.gas_used.as_usize() as u32, - hash: format_hash(block.hash.unwrap()), + difficulty: block.header.difficulty, + extra_data: block.header.extra_data.clone(), + gas_limit: block.header.gas_limit.try_into().unwrap(), + gas_used: block.header.gas_used.try_into().unwrap(), + hash: block.header.hash.unwrap(), is_uncle, - logs_bloom: format_bytes_slice( - block.logs_bloom.unwrap().as_bytes(), - ), - miner: format_address(block.author.unwrap()), - mix_hash: block.mix_hash.map(format_hash), - nonce: format_nonce(block.nonce.unwrap()), - number: block.number.unwrap().as_usize() as u32, - parent_hash: format_hash(block.parent_hash), - receipts_root: format_hash(block.receipts_root), - sha3_uncles: format_hash(block.uncles_hash), - size: block.size.unwrap().as_usize() as u32, - state_root: format_hash(block.state_root), - timestamp: block.timestamp.as_usize() as u32, - total_difficulty: block.total_difficulty, + logs_bloom: block.header.logs_bloom, + miner: block.header.miner, + mix_hash: block.header.mix_hash, + nonce: block.header.nonce.unwrap_or_default(), + number: block.header.number.unwrap().try_into().unwrap(), + parent_hash: block.header.parent_hash, + receipts_root: block.header.receipts_root, + sha3_uncles: block.header.uncles_hash, + size: block.size.unwrap().try_into().unwrap(), + state_root: block.header.state_root, + timestamp: block.header.timestamp.try_into().unwrap(), + total_difficulty: block.header.total_difficulty, transactions: block.transactions.len() as u16, - transactions_root: format_hash(block.transactions_root), - uncles: block - .uncles - .clone() - .into_iter() - .map(format_hash) - .collect(), - withdrawals_root, + transactions_root: block.header.transactions_root, + uncles: block.uncles.clone(), + withdrawals_root: block.header.withdrawals_root, } } } diff --git a/src/db/models/contract.rs b/src/db/models/contract.rs index a16361c..8e467fe 100644 --- a/src/db/models/contract.rs +++ b/src/db/models/contract.rs @@ -1,28 +1,27 @@ +use alloy::primitives::{Address, B256}; +use alloy::rpc::types::TransactionReceipt; use clickhouse::Row; -use ethers::types::TransactionReceipt; use serde::{Deserialize, Serialize}; +use serde_with::serde_as; -use crate::utils::format::{format_address, format_hash}; - +#[serde_as] #[derive(Debug, Clone, Row, Serialize, Deserialize)] pub struct DatabaseContract { pub block_number: u32, pub chain: u64, - pub contract_address: String, - pub creator: String, - pub transaction_hash: String, + pub contract_address: Address, + pub creator: Address, + pub transaction_hash: B256, } impl DatabaseContract { pub fn from_rpc(receipt: &TransactionReceipt, chain: u64) -> Self { Self { - block_number: receipt.block_number.unwrap().as_usize() as u32, + block_number: receipt.block_number.unwrap() as u32, chain, - contract_address: format_address( - receipt.contract_address.unwrap(), - ), - creator: format_address(receipt.from), - transaction_hash: format_hash(receipt.transaction_hash), + contract_address: receipt.contract_address.unwrap(), + creator: receipt.from, + transaction_hash: receipt.transaction_hash, } } } diff --git a/src/db/models/dex_trade.rs b/src/db/models/dex_trade.rs new file mode 100644 index 0000000..be522ef --- /dev/null +++ b/src/db/models/dex_trade.rs @@ -0,0 +1,530 @@ +use alloy::primitives::{Address, B256}; +use alloy::rpc::types::Log; +use clickhouse::Row; +use serde::{Deserialize, Serialize}; + +/// Negate a 256-bit two's complement number to get absolute value +/// Used for converting negative int256 values from V3 swap events +fn negate_i256(bytes: &[u8]) -> [u8; 32] { + let mut result = [0u8; 32]; + let mut carry = true; + + // Two's complement negation: invert all bits and add 1 + for i in (0..32).rev() { + let inverted = !bytes[i]; + if carry { + let (sum, overflow) = inverted.overflowing_add(1); + result[i] = sum; + carry = overflow; + } else { + result[i] = inverted; + } + } + + result +} + +#[derive(Debug, Clone, Row, Serialize, Deserialize)] +pub struct DatabaseDexTrade { + pub block_number: u32, + pub chain: u64, + pub transaction_hash: B256, + pub log_index: u16, + pub pool_address: Address, + pub sender: Address, + pub recipient: Address, + pub amount0_in: String, + pub amount1_in: String, + pub amount0_out: String, + pub amount1_out: String, + pub dex_name: String, + pub timestamp: u32, +} + +impl DatabaseDexTrade { + /// Create DatabaseDexTrade from Uniswap V2-style Swap event + /// Event: Swap(address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to) + /// Used by: Uniswap V2, PancakeSwap V2, SushiSwap V2, QuickSwap V2, etc. + pub fn from_uniswap_v2_swap( + log: &Log, + chain: u64, + block_number: u32, + timestamp: u32, + transaction_hash: B256, + log_index: u16, + dex_name: String, + ) -> Option { + if log.topics().len() < 3 { + return None; + } + + let sender = + Address::from_slice(&log.topics()[1].as_slice()[12..]); + let recipient = + Address::from_slice(&log.topics()[2].as_slice()[12..]); + + let data = &log.data().data; + if data.len() < 128 { + return None; + } + + Some(Self { + block_number, + chain, + transaction_hash, + log_index, + pool_address: log.address(), + sender, + recipient, + amount0_in: format!("0x{}", hex::encode(&data[0..32])), + amount1_in: format!("0x{}", hex::encode(&data[32..64])), + amount0_out: format!("0x{}", hex::encode(&data[64..96])), + amount1_out: format!("0x{}", hex::encode(&data[96..128])), + dex_name, + timestamp, + }) + } + + /// Create DatabaseDexTrade from Uniswap V3-style Swap event + /// Event: Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick) + /// Used by: Uniswap V3, PancakeSwap V3, etc. + pub fn from_uniswap_v3_swap( + log: &Log, + chain: u64, + block_number: u32, + timestamp: u32, + transaction_hash: B256, + log_index: u16, + dex_name: String, + ) -> Option { + if log.topics().len() < 3 { + return None; + } + + let sender = + Address::from_slice(&log.topics()[1].as_slice()[12..]); + let recipient = + Address::from_slice(&log.topics()[2].as_slice()[12..]); + + let data = &log.data().data; + if data.len() < 160 { + return None; + } + + // V3 amounts are signed integers (int256) + // Positive = tokens going INTO the pool (user sends) + // Negative = tokens going OUT of the pool (user receives) + let is_amount0_negative = data[0] & 0x80 != 0; + let is_amount1_negative = data[32] & 0x80 != 0; + + // For negative amounts, compute absolute value (negate two's complement) + let (amount0_in, amount0_out) = if !is_amount0_negative { + // Positive: user sends this amount (amount_in) + (format!("0x{}", hex::encode(&data[0..32])), "0x0".to_string()) + } else { + // Negative: user receives this amount (amount_out) - compute absolute value + let abs_amount = negate_i256(&data[0..32]); + ("0x0".to_string(), format!("0x{}", hex::encode(abs_amount))) + }; + + let (amount1_in, amount1_out) = if !is_amount1_negative { + ( + format!("0x{}", hex::encode(&data[32..64])), + "0x0".to_string(), + ) + } else { + let abs_amount = negate_i256(&data[32..64]); + ("0x0".to_string(), format!("0x{}", hex::encode(abs_amount))) + }; + + Some(Self { + block_number, + chain, + transaction_hash, + log_index, + pool_address: log.address(), + sender, + recipient, + amount0_in, + amount1_in, + amount0_out, + amount1_out, + dex_name, + timestamp, + }) + } + + /// Create DatabaseDexTrade from Curve TokenExchange event + /// Event: TokenExchange(address indexed buyer, uint256 sold_id, uint256 tokens_sold, uint256 bought_id, uint256 tokens_bought) + pub fn from_curve_token_exchange( + log: &Log, + chain: u64, + block_number: u32, + timestamp: u32, + transaction_hash: B256, + log_index: u16, + ) -> Option { + if log.topics().len() < 2 { + return None; + } + + let buyer = Address::from_slice(&log.topics()[1].as_slice()[12..]); + + let data = &log.data().data; + if data.len() < 128 { + return None; + } + + // Curve: sold_id, tokens_sold, bought_id, tokens_bought + let tokens_sold = format!("0x{}", hex::encode(&data[32..64])); + let tokens_bought = format!("0x{}", hex::encode(&data[96..128])); + + Some(Self { + block_number, + chain, + transaction_hash, + log_index, + pool_address: log.address(), + sender: buyer, + recipient: buyer, // Curve doesn't have separate recipient + amount0_in: tokens_bought, + amount1_in: "0x0".to_string(), + amount0_out: tokens_sold, + amount1_out: "0x0".to_string(), + dex_name: "Curve".to_string(), + timestamp, + }) + } + + /// Create DatabaseDexTrade from Balancer Swap event + /// Event: Swap(bytes32 indexed poolId, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut) + pub fn from_balancer_swap( + log: &Log, + chain: u64, + block_number: u32, + timestamp: u32, + transaction_hash: B256, + log_index: u16, + dex_name: String, + ) -> Option { + if log.topics().len() < 4 { + return None; + } + + let token_in = + Address::from_slice(&log.topics()[2].as_slice()[12..]); + let token_out = + Address::from_slice(&log.topics()[3].as_slice()[12..]); + + let data = &log.data().data; + if data.len() < 64 { + return None; + } + + let amount_in = format!("0x{}", hex::encode(&data[0..32])); + let amount_out = format!("0x{}", hex::encode(&data[32..64])); + + Some(Self { + block_number, + chain, + transaction_hash, + log_index, + pool_address: log.address(), + sender: token_in, + recipient: token_out, + amount0_in: amount_in, + amount1_in: "0x0".to_string(), + amount0_out: amount_out, + amount1_out: "0x0".to_string(), + dex_name, + timestamp, + }) + } + + /// Create DatabaseDexTrade from DODO Swap event + /// Event: Swap(address indexed sender, address indexed receiver, address tokenB, address tokenQuote, uint256 payQuote, uint256 receiveBase) + pub fn from_dodo_swap( + log: &Log, + chain: u64, + block_number: u32, + timestamp: u32, + transaction_hash: B256, + log_index: u16, + dex_name: String, + ) -> Option { + if log.topics().len() < 3 { + return None; + } + + let sender = + Address::from_slice(&log.topics()[1].as_slice()[12..]); + let receiver = + Address::from_slice(&log.topics()[2].as_slice()[12..]); + + let data = &log.data().data; + if data.len() < 160 { + return None; + } + + // Skip first 2 addresses (tokenB, tokenQuote) as they're 32-byte aligned + // payQuote is at offset 64, receiveBase at offset 96 + let pay_quote = format!("0x{}", hex::encode(&data[64..96])); + let receive_base = format!("0x{}", hex::encode(&data[96..128])); + + Some(Self { + block_number, + chain, + transaction_hash, + log_index, + pool_address: log.address(), + sender, + recipient: receiver, + amount0_in: pay_quote, + amount1_in: "0x0".to_string(), + amount0_out: receive_base, + amount1_out: "0x0".to_string(), + dex_name, + timestamp, + }) + } + + /// Create DatabaseDexTrade from Kyber Swapped event + /// Event: Swapped(address indexed sender, IERC20 indexed srcToken, IERC20 indexed dstToken, address dstReceiver, uint256 spentAmount, uint256 returnedAmount) + /// Note: EVM logs support max 4 topics (topic0 = signature + 3 indexed params) + pub fn from_kyber_swapped( + log: &Log, + chain: u64, + block_number: u32, + timestamp: u32, + transaction_hash: B256, + log_index: u16, + dex_name: String, + ) -> Option { + if log.topics().len() < 4 { + return None; + } + + let sender = + Address::from_slice(&log.topics()[1].as_slice()[12..]); + + let data = &log.data().data; + // Data: dstReceiver (32) + spentAmount (32) + returnedAmount (32) = 96 bytes + if data.len() < 96 { + return None; + } + + // Skip dstReceiver at offset 0-32 + let spent_amount = format!("0x{}", hex::encode(&data[32..64])); + let returned_amount = format!("0x{}", hex::encode(&data[64..96])); + + Some(Self { + block_number, + chain, + transaction_hash, + log_index, + pool_address: log.address(), + sender, + recipient: Address::from_slice(&data[12..32]), // dstReceiver + amount0_in: spent_amount, + amount1_in: "0x0".to_string(), + amount0_out: returned_amount, + amount1_out: "0x0".to_string(), + dex_name, + timestamp, + }) + } + + /// Create DatabaseDexTrade from Maverick SwapFilled event + /// Event: SwapFilled(address indexed recipient, uint256 amountAIn, uint256 amountBIn, uint256 amountAOut, uint256 amountBOut) + pub fn from_maverick_swap_filled( + log: &Log, + chain: u64, + block_number: u32, + timestamp: u32, + transaction_hash: B256, + log_index: u16, + dex_name: String, + ) -> Option { + if log.topics().len() < 2 { + return None; + } + + let recipient = + Address::from_slice(&log.topics()[1].as_slice()[12..]); + + let data = &log.data().data; + // 4 x uint256 = 128 bytes + if data.len() < 128 { + return None; + } + + let amount_a_in = format!("0x{}", hex::encode(&data[0..32])); + let amount_b_in = format!("0x{}", hex::encode(&data[32..64])); + let amount_a_out = format!("0x{}", hex::encode(&data[64..96])); + let amount_b_out = format!("0x{}", hex::encode(&data[96..128])); + + Some(Self { + block_number, + chain, + transaction_hash, + log_index, + pool_address: log.address(), + sender: recipient, + recipient, + amount0_in: amount_a_in, + amount1_in: amount_b_in, + amount0_out: amount_a_out, + amount1_out: amount_b_out, + dex_name, + timestamp, + }) + } + + /// Create DatabaseDexTrade from Curve TokenExchangeUnderlying event + /// Event: TokenExchangeUnderlying(address indexed buyer, int128 sold_id, uint256 tokens_sold, int128 bought_id, uint256 tokens_bought) + /// Used for meta pools where users swap underlying tokens directly + pub fn from_curve_token_exchange_underlying( + log: &Log, + chain: u64, + block_number: u32, + timestamp: u32, + transaction_hash: B256, + log_index: u16, + ) -> Option { + if log.topics().len() < 2 { + return None; + } + + let buyer = Address::from_slice(&log.topics()[1].as_slice()[12..]); + + let data = &log.data().data; + // int128 sold_id (32) + uint256 tokens_sold (32) + int128 bought_id (32) + uint256 tokens_bought (32) = 128 bytes + if data.len() < 128 { + return None; + } + + // Skip sold_id at offset 0-32, extract tokens_sold at offset 32-64 + let tokens_sold = format!("0x{}", hex::encode(&data[32..64])); + // Skip bought_id at offset 64-96, extract tokens_bought at offset 96-128 + let tokens_bought = format!("0x{}", hex::encode(&data[96..128])); + + Some(Self { + block_number, + chain, + transaction_hash, + log_index, + pool_address: log.address(), + sender: buyer, + recipient: buyer, // Curve doesn't have separate recipient + amount0_in: tokens_sold, + amount1_in: "0x0".to_string(), + amount0_out: tokens_bought, + amount1_out: "0x0".to_string(), + dex_name: "Curve".to_string(), + timestamp, + }) + } + + /// Create DatabaseDexTrade from TraderJoe V2.1 LB Swap event + /// Event: Swap(address indexed sender, address indexed to, uint24 id, bytes32 amountsIn, bytes32 amountsOut) + /// The amountsIn and amountsOut are packed as (amountX, amountY) where X is token0 and Y is token1 + pub fn from_traderjoe_lb_swap( + log: &Log, + chain: u64, + block_number: u32, + timestamp: u32, + transaction_hash: B256, + log_index: u16, + dex_name: String, + ) -> Option { + if log.topics().len() < 3 { + return None; + } + + let sender = + Address::from_slice(&log.topics()[1].as_slice()[12..]); + let recipient = + Address::from_slice(&log.topics()[2].as_slice()[12..]); + + let data = &log.data().data; + // uint24 id (32 padded) + bytes32 amountsIn (32) + bytes32 amountsOut (32) = 96 bytes + if data.len() < 96 { + return None; + } + + // amountsIn is packed as (amountXIn, amountYIn) in bytes32 + // amountsOut is packed as (amountXOut, amountYOut) in bytes32 + // The packing is: upper 128 bits = amountX, lower 128 bits = amountY + let amounts_in = &data[32..64]; + let amounts_out = &data[64..96]; + + // Extract amounts (upper 16 bytes = tokenX, lower 16 bytes = tokenY) + let amount0_in = format!("0x{}", hex::encode(&amounts_in[0..16])); + let amount1_in = format!("0x{}", hex::encode(&amounts_in[16..32])); + let amount0_out = + format!("0x{}", hex::encode(&amounts_out[0..16])); + let amount1_out = + format!("0x{}", hex::encode(&amounts_out[16..32])); + + Some(Self { + block_number, + chain, + transaction_hash, + log_index, + pool_address: log.address(), + sender, + recipient, + amount0_in, + amount1_in, + amount0_out, + amount1_out, + dex_name, + timestamp, + }) + } + + /// Create DatabaseDexTrade from WooFi WooSwap event + /// Event: WooSwap(address indexed from, address indexed to, address fromToken, address toToken, uint256 fromAmount, uint256 toAmount, address rebateTo) + pub fn from_woofi_swap( + log: &Log, + chain: u64, + block_number: u32, + timestamp: u32, + transaction_hash: B256, + log_index: u16, + ) -> Option { + if log.topics().len() < 3 { + return None; + } + + let sender = + Address::from_slice(&log.topics()[1].as_slice()[12..]); + let recipient = + Address::from_slice(&log.topics()[2].as_slice()[12..]); + + let data = &log.data().data; + // fromToken (32) + toToken (32) + fromAmount (32) + toAmount (32) + rebateTo (32) = 160 bytes + if data.len() < 160 { + return None; + } + + let from_amount = format!("0x{}", hex::encode(&data[64..96])); + let to_amount = format!("0x{}", hex::encode(&data[96..128])); + + Some(Self { + block_number, + chain, + transaction_hash, + log_index, + pool_address: log.address(), + sender, + recipient, + amount0_in: from_amount, + amount1_in: "0x0".to_string(), + amount0_out: to_amount, + amount1_out: "0x0".to_string(), + dex_name: "WooFi".to_string(), + timestamp, + }) + } +} diff --git a/src/db/models/erc1155_transfer.rs b/src/db/models/erc1155_transfer.rs index 9eefdee..7873951 100644 --- a/src/db/models/erc1155_transfer.rs +++ b/src/db/models/erc1155_transfer.rs @@ -1,176 +1,85 @@ +use alloy::primitives::{Address, B256, U256}; use clickhouse::Row; -use ethers::abi::{ethabi, ParamType}; -use primitive_types::{H256, U256}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use super::log::DatabaseLog; -use crate::utils::format::{format_address, SerU256}; +use crate::utils::format::SerU256; #[serde_as] #[derive(Debug, Clone, Row, Serialize, Deserialize)] pub struct DatabaseERC1155Transfer { - pub address: String, + pub address: Address, #[serde_as(as = "Vec")] pub amounts: Vec, pub block_number: u32, pub chain: u64, - pub from: String, + pub from: Address, #[serde_as(as = "Vec")] pub ids: Vec, pub log_index: u16, pub log_type: Option, - pub operator: String, + pub operator: Address, pub removed: bool, pub timestamp: u32, - pub to: String, - pub token_address: String, - pub transaction_hash: String, + pub to: Address, + pub token_address: Address, + pub transaction_hash: B256, pub transaction_log_index: Option, } impl DatabaseERC1155Transfer { - pub fn from_single_rpc( - log: &DatabaseLog, - id: U256, - amount: U256, - ) -> Self { - let operator_bytes = - array_bytes::dehexify_array_then_into::( - log.topic1.clone().unwrap(), - ) + pub fn from_log(log: &DatabaseLog) -> Option { + let topic0 = log.topic0?; + let topic1 = log.topic1?; + let topic2 = log.topic2?; + let topic3 = log.topic3?; + + let single = "0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62" + .parse::() .unwrap(); - - let from_address_bytes = - array_bytes::dehexify_array_then_into::( - log.topic2.clone().unwrap(), - ) - .unwrap(); - - let to_address_bytes = - array_bytes::dehexify_array_then_into::( - log.topic3.clone().unwrap(), - ) + let batch = "0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb" + .parse::() .unwrap(); - let operator_tokens = ethabi::decode( - &[ParamType::Address], - operator_bytes.as_bytes(), - ) - .unwrap(); - - let operator = operator_tokens.first().unwrap(); - - let from_address_tokens = ethabi::decode( - &[ParamType::Address], - from_address_bytes.as_bytes(), - ) - .unwrap(); - - let from_address = from_address_tokens.first().unwrap(); - - let to_address_tokens = ethabi::decode( - &[ParamType::Address], - to_address_bytes.as_bytes(), - ) - .unwrap(); - - let to_address = to_address_tokens.first().unwrap(); - - Self { - address: log.address.clone(), - amounts: vec![amount], - block_number: log.block_number, - chain: log.chain, - from: format_address( - from_address.to_owned().into_address().unwrap(), - ), - ids: vec![id], - log_index: log.log_index, - log_type: log.log_type.clone(), - operator: format_address( - operator.to_owned().into_address().unwrap(), - ), - removed: log.removed, - timestamp: log.timestamp, - to: format_address( - to_address.to_owned().into_address().unwrap(), - ), - token_address: log.address.clone(), - transaction_hash: log.transaction_hash.clone(), - transaction_log_index: log.transaction_log_index, + if topic0 != single && topic0 != batch { + return None; } - } - - pub fn from_batch_rpc( - log: &DatabaseLog, - ids: Vec, - amounts: Vec, - ) -> Self { - let operator_bytes = - array_bytes::dehexify_array_then_into::( - log.topic1.clone().unwrap(), - ) - .unwrap(); - - let from_address_bytes = - array_bytes::dehexify_array_then_into::( - log.topic2.clone().unwrap(), - ) - .unwrap(); - - let to_address_bytes = - array_bytes::dehexify_array_then_into::( - log.topic3.clone().unwrap(), - ) - .unwrap(); - let operator_tokens = ethabi::decode( - &[ParamType::Address], - operator_bytes.as_bytes(), - ) - .unwrap(); - - let operator = operator_tokens.first().unwrap(); - - let from_address_tokens = ethabi::decode( - &[ParamType::Address], - from_address_bytes.as_bytes(), - ) - .unwrap(); - - let from_address = from_address_tokens.first().unwrap(); - - let to_address_tokens = ethabi::decode( - &[ParamType::Address], - to_address_bytes.as_bytes(), - ) - .unwrap(); - - let to_address = to_address_tokens.first().unwrap(); + let operator = Address::from_word(topic1); + let from = Address::from_word(topic2); + let to = Address::from_word(topic3); + + let mut ids = Vec::new(); + let mut amounts = Vec::new(); + + if topic0 == single { + if log.data.len() >= 64 { + let id = U256::from_be_slice(&log.data[0..32]); + let amount = U256::from_be_slice(&log.data[32..64]); + ids.push(id); + amounts.push(amount); + } + } else { + return None; // Batch decoding skipped for now + } - Self { - address: log.address.clone(), + Some(Self { + address: log.address, amounts, block_number: log.block_number, chain: log.chain, - from: format_address( - from_address.to_owned().into_address().unwrap(), - ), + from, ids, log_index: log.log_index, log_type: log.log_type.clone(), - operator: format_address( - operator.to_owned().into_address().unwrap(), - ), + operator, removed: log.removed, timestamp: log.timestamp, - to: format_address( - to_address.to_owned().into_address().unwrap(), - ), - token_address: log.address.clone(), - transaction_hash: log.transaction_hash.clone(), + to, + token_address: log.address, + transaction_hash: log.transaction_hash, transaction_log_index: log.transaction_log_index, - } + }) } } diff --git a/src/db/models/erc20_transfer.rs b/src/db/models/erc20_transfer.rs index 43dd22e..95d3c92 100644 --- a/src/db/models/erc20_transfer.rs +++ b/src/db/models/erc20_transfer.rs @@ -1,87 +1,66 @@ +use alloy::primitives::{Address, B256, U256}; use clickhouse::Row; -use ethers::abi::{ethabi, ParamType}; -use primitive_types::{H256, U256}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use super::log::DatabaseLog; -use crate::utils::format::{decode_bytes, format_address, SerU256}; +use crate::utils::format::SerU256; #[serde_as] #[derive(Debug, Clone, Row, Serialize, Deserialize)] pub struct DatabaseERC20Transfer { - pub address: String, + pub address: Address, #[serde_as(as = "SerU256")] pub amount: U256, pub block_number: u32, pub chain: u64, - pub from: String, + pub from: Address, pub log_index: u16, pub log_type: Option, pub removed: bool, pub timestamp: u32, - pub to: String, - pub token_address: String, - pub transaction_hash: String, + pub to: Address, + pub token_address: Address, + pub transaction_hash: B256, pub transaction_log_index: Option, } impl DatabaseERC20Transfer { - pub fn from_rpc(log: &DatabaseLog) -> Self { - let from_address_bytes = - array_bytes::dehexify_array_then_into::( - log.topic0.clone(), - ) - .unwrap(); + pub fn from_log(log: &DatabaseLog) -> Option { + let topic0 = log.topic0?; + let topic1 = log.topic1?; + let topic2 = log.topic2?; - let to_address_bytes = - array_bytes::dehexify_array_then_into::( - log.topic2.clone().unwrap(), - ) - .unwrap(); - - let from_address_tokens = ethabi::decode( - &[ParamType::Address], - from_address_bytes.as_bytes(), - ) - .unwrap(); - - let from_address = from_address_tokens.first().unwrap(); - - let to_address_tokens = ethabi::decode( - &[ParamType::Address], - to_address_bytes.as_bytes(), - ) - .unwrap(); - - let to_address = to_address_tokens.first().unwrap(); - - let log_data = decode_bytes(log.data.clone()); + if topic0 + != "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + .parse::() + .unwrap() + { + return None; + } - let value_tokens = - ethabi::decode(&[ParamType::Uint(256)], &log_data[..]) - .unwrap(); + if log.topic3.is_some() { + return None; + } - let value = value_tokens.first().unwrap(); + let from = Address::from_word(topic1); + let to = Address::from_word(topic2); + let amount = U256::from_be_slice(&log.data); - Self { - address: log.address.clone(), - amount: value.to_owned().into_uint().unwrap(), + Some(Self { + address: log.address, + amount, block_number: log.block_number, chain: log.chain, - from: format_address( - from_address.to_owned().into_address().unwrap(), - ), + from, log_index: log.log_index, log_type: log.log_type.clone(), removed: log.removed, timestamp: log.timestamp, - to: format_address( - to_address.to_owned().into_address().unwrap(), - ), - token_address: log.address.clone(), - transaction_hash: log.transaction_hash.clone(), + to, + token_address: log.address, + transaction_hash: log.transaction_hash, transaction_log_index: log.transaction_log_index, - } + }) } } diff --git a/src/db/models/erc721_transfer.rs b/src/db/models/erc721_transfer.rs index 82a578e..53277bf 100644 --- a/src/db/models/erc721_transfer.rs +++ b/src/db/models/erc721_transfer.rs @@ -1,91 +1,63 @@ +use alloy::primitives::{Address, B256, U256}; use clickhouse::Row; -use ethers::abi::{ethabi, ParamType}; -use primitive_types::{H256, U256}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use super::log::DatabaseLog; -use crate::utils::format::{format_address, SerU256}; +use crate::utils::format::SerU256; #[serde_as] #[derive(Debug, Clone, Row, Serialize, Deserialize)] pub struct DatabaseERC721Transfer { - pub address: String, + pub address: Address, pub block_number: u32, pub chain: u64, - pub from: String, + pub from: Address, #[serde_as(as = "SerU256")] pub id: U256, pub log_index: u16, pub log_type: Option, pub removed: bool, pub timestamp: u32, - pub to: String, - pub token_address: String, - pub transaction_hash: String, + pub to: Address, + pub token_address: Address, + pub transaction_hash: B256, pub transaction_log_index: Option, } impl DatabaseERC721Transfer { - pub fn from_rpc(log: &DatabaseLog) -> Self { - let from_address_bytes = - array_bytes::dehexify_array_then_into::( - log.topic1.clone().unwrap(), - ) - .unwrap(); - - let to_address_bytes = - array_bytes::dehexify_array_then_into::( - log.topic2.clone().unwrap(), - ) - .unwrap(); - - let id_bytes = - array_bytes::dehexify_array_then_into::( - log.topic3.clone().unwrap(), - ) - .unwrap(); - - let from_address_tokens = ethabi::decode( - &[ParamType::Address], - from_address_bytes.as_bytes(), - ) - .unwrap(); - - let from_address = from_address_tokens.first().unwrap(); - - let to_address_tokens = ethabi::decode( - &[ParamType::Address], - to_address_bytes.as_bytes(), - ) - .unwrap(); - - let to_address = to_address_tokens.first().unwrap(); - - let id_tokens = - ethabi::decode(&[ParamType::Uint(256)], id_bytes.as_bytes()) - .unwrap(); + pub fn from_log(log: &DatabaseLog) -> Option { + let topic0 = log.topic0?; + let topic1 = log.topic1?; + let topic2 = log.topic2?; + let topic3 = log.topic3?; + + if topic0 + != "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" + .parse::() + .unwrap() + { + return None; + } - let id = id_tokens.first().unwrap(); + let from = Address::from_word(topic1); + let to = Address::from_word(topic2); + let id = U256::from_be_bytes(topic3.0); - Self { - address: log.address.clone(), + Some(Self { + address: log.address, block_number: log.block_number, chain: log.chain, - from: format_address( - from_address.to_owned().into_address().unwrap(), - ), - id: id.to_owned().into_uint().unwrap(), + from, + id, log_index: log.log_index, log_type: log.log_type.clone(), removed: log.removed, timestamp: log.timestamp, - to: format_address( - to_address.to_owned().into_address().unwrap(), - ), - token_address: log.address.clone(), - transaction_hash: log.transaction_hash.clone(), + to, + token_address: log.address, + transaction_hash: log.transaction_hash, transaction_log_index: log.transaction_log_index, - } + }) } } diff --git a/src/db/models/log.rs b/src/db/models/log.rs index 8d5a8e8..a7e86ba 100644 --- a/src/db/models/log.rs +++ b/src/db/models/log.rs @@ -1,26 +1,25 @@ +use alloy::primitives::{Address, Bytes, B256}; +use alloy::rpc::types::Log; use clickhouse::Row; -use ethers::types::Log; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use crate::utils::format::{format_address, format_bytes, format_hash}; - #[serde_as] #[derive(Debug, Clone, Row, Serialize, Deserialize)] pub struct DatabaseLog { - pub address: String, + pub address: Address, pub block_number: u32, pub chain: u64, - pub data: String, + pub data: Bytes, pub log_index: u16, pub log_type: Option, pub removed: bool, pub timestamp: u32, - pub topic0: String, - pub topic1: Option, - pub topic2: Option, - pub topic3: Option, - pub transaction_hash: String, + pub topic0: Option, + pub topic1: Option, + pub topic2: Option, + pub topic3: Option, + pub transaction_hash: B256, pub transaction_log_index: Option, } @@ -31,51 +30,49 @@ impl DatabaseLog { timestamp: u32, block_number: &u32, ) -> Self { - let topic0 = if log.topics.is_empty() { - String::from("0x") + let topic0 = if log.topics().is_empty() { + None } else { - format_hash(log.topics[0]) + Some(log.topics()[0]) }; - let topics = log.topics.len(); - - let topic1 = if topics < 2 { + let topic1 = if log.topics().len() < 2 { None } else { - Some(format_hash(log.topics[1])) + Some(log.topics()[1]) }; - let topic2 = if topics < 3 { + let topic2 = if log.topics().len() < 3 { None } else { - Some(format_hash(log.topics[2])) + Some(log.topics()[2]) }; - let topic3 = if topics < 4 { + let topic3 = if log.topics().len() < 4 { None } else { - Some(format_hash(log.topics[3])) + Some(log.topics()[3]) }; - let transaction_log_index: Option = - log.transaction_log_index.map(|transaction_log_index| { - transaction_log_index.as_usize() as u16 - }); + let transaction_log_index = log + .transaction_index + .map(|transaction_log_index| transaction_log_index as u16); Self { - address: format_address(log.address), - block_number: block_number.to_owned(), + address: log.address(), + block_number: *block_number, chain, - data: format_bytes(&log.data), - log_index: log.log_index.unwrap().as_usize() as u16, - log_type: log.log_type.clone(), - removed: log.removed.unwrap(), + data: log.data().data.clone(), + log_index: log.log_index.unwrap() as u16, + log_type: None, + removed: log.removed, timestamp, topic0, topic1, topic2, topic3, - transaction_hash: format_hash(log.transaction_hash.unwrap()), + + transaction_hash: log.transaction_hash.unwrap(), transaction_log_index, } } diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs index 96e95dc..ca49442 100644 --- a/src/db/models/mod.rs +++ b/src/db/models/mod.rs @@ -1,5 +1,6 @@ pub mod block; pub mod contract; +pub mod dex_trade; pub mod erc1155_transfer; pub mod erc20_transfer; pub mod erc721_transfer; diff --git a/src/db/models/trace.rs b/src/db/models/trace.rs index 90c7d78..bf5fd34 100644 --- a/src/db/models/trace.rs +++ b/src/db/models/trace.rs @@ -1,34 +1,34 @@ +use crate::utils::format::SerU256; +use alloy::primitives::{Address, Bytes, B256, U256}; +use alloy_rpc_types_trace::parity::{ + Action, CallType as AlloyCallType, LocalizedTransactionTrace as Trace, + RewardType as AlloyRewardType, TraceOutput as Res, +}; use clickhouse::Row; -use ethers::types::Trace; -use primitive_types::U256; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_with::serde_as; -use crate::utils::format::{ - format_address, format_bytes, format_hash, SerU256, -}; - #[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)] #[repr(u8)] -pub enum TraceType { +pub enum ActionType { Call = 1, Create = 2, Suicide = 3, Reward = 4, } -#[derive(Debug, Clone, Serialize_repr, Deserialize_repr)] +#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)] #[repr(u8)] pub enum CallType { None = 0, Call = 1, - Callcode = 2, + CallCode = 2, DelegateCall = 3, StaticCall = 4, } -#[derive(Debug, Clone, Serialize_repr, Deserialize_repr)] +#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)] #[repr(u8)] pub enum RewardType { Block = 1, @@ -40,29 +40,29 @@ pub enum RewardType { #[serde_as] #[derive(Debug, Clone, Row, Serialize, Deserialize)] pub struct DatabaseTrace { - pub action_type: TraceType, - pub address: Option, - pub author: Option, + pub action_type: String, + pub address: Option
, + pub author: Option
, #[serde_as(as = "Option")] pub balance: Option, - pub block_hash: String, + pub block_hash: B256, pub block_number: u32, - pub call_type: Option, + pub call_type: Option, pub chain: u64, - pub code: Option, + pub code: Option, pub error: Option, - pub from: Option, + pub from: Option
, pub gas: Option, pub gas_used: Option, - pub init: Option, - pub input: Option, - pub output: Option, - pub refund_address: Option, - pub reward_type: Option, + pub init: Option, + pub input: Option, + pub output: Option, + pub refund_address: Option
, + pub reward_type: Option, pub subtraces: u16, - pub to: Option, + pub to: Option
, pub trace_address: Vec, - pub transaction_hash: Option, + pub transaction_hash: Option, pub transaction_position: Option, #[serde_as(as = "Option")] pub value: Option, @@ -70,127 +70,100 @@ pub struct DatabaseTrace { impl DatabaseTrace { pub fn from_rpc(trace: &Trace, chain: u64) -> Self { - let trace_address = trace - .trace_address - .clone() - .into_iter() - .map(|n| n as u16) - .collect(); - - let transaction_position: Option = trace - .transaction_position - .map(|transaction_position| transaction_position as u16); - - let action_type = match trace.action_type { - ethers::types::ActionType::Call => TraceType::Call, - ethers::types::ActionType::Create => TraceType::Create, - ethers::types::ActionType::Suicide => TraceType::Suicide, - ethers::types::ActionType::Reward => TraceType::Reward, - }; - - let transaction_hash: Option = - trace.transaction_hash.map(format_hash); - - let mut from: Option = None; - let mut to: Option = None; + let mut call_type: Option = None; + let mut reward_type: Option = None; + let mut from: Option
= None; + let mut to: Option
= None; let mut gas: Option = None; + let mut input: Option = None; let mut value: Option = None; - let mut input: Option = None; - let mut call_type: Option = None; - let mut init: Option = None; - let mut address: Option = None; - let mut refund_address: Option = None; + let mut init: Option = None; + let mut address: Option
= None; + let mut refund_address: Option
= None; + let mut author: Option
= None; let mut balance: Option = None; - let mut author: Option = None; - let mut reward_type: Option = None; - - match trace.action.clone() { - ethers::types::Action::Call(call) => { - from = Some(format_address(call.from)); - to = Some(format_address(call.to)); + let action_type = match &trace.trace.action { + Action::Call(call) => { + from = Some(call.from); + to = Some(call.to); + gas = Some(call.gas.to::()); + input = Some(call.input.clone()); value = Some(call.value); - gas = Some(call.gas.as_usize() as u32); - input = Some(format_bytes(&call.input)); call_type = match call.call_type { - ethers::types::CallType::None => Some(CallType::None), - ethers::types::CallType::Call => Some(CallType::Call), - ethers::types::CallType::CallCode => { - Some(CallType::Callcode) + AlloyCallType::None => Some("none".to_string()), + AlloyCallType::Call => Some("call".to_string()), + AlloyCallType::CallCode => { + Some("callcode".to_string()) } - ethers::types::CallType::DelegateCall => { - Some(CallType::DelegateCall) + AlloyCallType::DelegateCall => { + Some("delegatecall".to_string()) } - ethers::types::CallType::StaticCall => { - Some(CallType::StaticCall) + AlloyCallType::StaticCall => { + Some("staticcall".to_string()) } - } + AlloyCallType::AuthCall => Some("none".to_string()), + }; + "call".to_string() } - ethers::types::Action::Create(create) => { - from = Some(format_address(create.from)); + Action::Create(create) => { + from = Some(create.from); value = Some(create.value); - gas = Some(create.gas.as_usize() as u32); - init = Some(format_bytes(&create.init)); + gas = Some(create.gas.to::()); + init = Some(create.init.clone()); + "create".to_string() } - ethers::types::Action::Suicide(suicide) => { - address = Some(format_address(suicide.address)); - refund_address = - Some(format_address(suicide.refund_address)); - balance = Some(suicide.balance) + Action::Selfdestruct(suicide) => { + from = Some(suicide.address); + refund_address = Some(suicide.refund_address); + balance = Some(suicide.balance); + "suicide".to_string() } - ethers::types::Action::Reward(reward) => { - author = Some(format_address(reward.author)); + Action::Reward(reward) => { + author = Some(reward.author); value = Some(reward.value); reward_type = match reward.reward_type { - ethers::types::RewardType::Block => { - Some(RewardType::Block) - } - ethers::types::RewardType::Uncle => { - Some(RewardType::Uncle) - } - - ethers::types::RewardType::EmptyStep => { - Some(RewardType::EmptyStep) - } - - ethers::types::RewardType::External => { - Some(RewardType::External) - } - } + AlloyRewardType::Block => Some("block".to_string()), + AlloyRewardType::Uncle => Some("uncle".to_string()), + }; + "reward".to_string() } - } + }; let mut gas_used: Option = None; - let mut output: Option = None; - let mut code: Option = None; + let mut output: Option = None; + let mut code: Option = None; + let mut address_output: Option
= None; - if trace.result.is_some() { - let result = trace.result.clone().unwrap(); + if let Some(result) = &trace.trace.result { match result { - ethers::types::Res::Call(call) => { - gas_used = Some(call.gas_used.as_usize() as u32); - output = Some(format_bytes(&call.output)) + Res::Call(call) => { + gas_used = Some(call.gas_used.to::()); + output = Some(call.output.clone()); } - ethers::types::Res::Create(create) => { - address = Some(format_address(create.address)); - gas_used = Some(create.gas_used.as_usize() as u32); - code = Some(format_bytes(&create.code)) + Res::Create(create) => { + gas_used = Some(create.gas_used.to::()); + code = Some(create.code.clone()); + address_output = Some(create.address); } - ethers::types::Res::None => (), } } + if address.is_none() && address_output.is_some() { + address = address_output; + } + Self { action_type, address, author, balance, - block_hash: format_hash(trace.block_hash), - block_number: trace.block_number as u32, + block_hash: trace.block_hash.unwrap(), + block_number: trace.block_number.unwrap() as u32, call_type, chain, code, - error: trace.error.clone(), + error: trace.trace.error.clone(), from, gas, gas_used, @@ -199,11 +172,18 @@ impl DatabaseTrace { output, refund_address, reward_type, - subtraces: trace.subtraces as u16, + subtraces: trace.trace.subtraces as u16, to, - trace_address, - transaction_hash, - transaction_position, + trace_address: trace + .trace + .trace_address + .iter() + .map(|v| *v as u16) + .collect(), + transaction_hash: trace.transaction_hash, + transaction_position: trace + .transaction_position + .map(|v| v as u16), value, } } diff --git a/src/db/models/transaction.rs b/src/db/models/transaction.rs index f779645..97dd9b1 100644 --- a/src/db/models/transaction.rs +++ b/src/db/models/transaction.rs @@ -1,13 +1,11 @@ +use alloy::primitives::{Address, Bytes, B256, U256}; +use alloy::rpc::types::{Transaction, TransactionReceipt}; use clickhouse::Row; -use ethers::types::{Transaction, TransactionReceipt}; -use primitive_types::{H160, U256}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_with::serde_as; -use crate::utils::format::{ - byte4_from_input, format_address, format_bytes, format_hash, SerU256, -}; +use crate::utils::format::SerU256; #[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)] #[repr(u8)] @@ -15,6 +13,7 @@ pub enum TransactionType { Legacy = 0, AccessList = 1, Eip1559 = 2, + Blob = 3, } #[serde_as] @@ -29,33 +28,33 @@ pub enum TransactionStatus { #[serde_as] #[derive(Debug, Clone, Row, Serialize, Deserialize)] pub struct DatabaseTransaction { - pub access_list: Vec<(String, Vec)>, + pub access_list: Vec<(Address, Vec)>, pub base_fee_per_gas: Option, - pub block_hash: String, + pub block_hash: B256, pub block_number: u32, pub chain: u64, - pub contract_created: Option, + pub contract_created: Option
, pub cumulative_gas_used: Option, #[serde_as(as = "Option")] pub effective_gas_price: Option, - pub from: String, + pub from: Address, pub gas: u32, #[serde_as(as = "Option")] pub gas_price: Option, pub gas_used: Option, - pub hash: String, - pub input: String, + pub hash: B256, + pub input: Bytes, #[serde_as(as = "Option")] pub max_fee_per_gas: Option, #[serde_as(as = "Option")] pub max_priority_fee_per_gas: Option, pub method: String, pub nonce: u32, - pub status: Option, + pub status: Option, pub timestamp: u32, - pub to: String, + pub to: Address, pub transaction_index: u16, - pub transaction_type: TransactionType, + pub transaction_type: String, #[serde_as(as = "SerU256")] pub value: U256, } @@ -63,43 +62,33 @@ pub struct DatabaseTransaction { impl DatabaseTransaction { pub fn from_rpc( transaction: &Transaction, + receipt: &TransactionReceipt, chain: u64, timestamp: u32, + base_fee_per_gas: Option, ) -> Self { - let to: String = match transaction.to { - Some(address) => format_address(address), - None => format_address(H160::zero()), - }; + let to = transaction.to.unwrap_or(Address::ZERO); - let transaction_type: TransactionType = + let transaction_type_str: String = match transaction.transaction_type { - Some(transaction_type) => { - if transaction_type.as_usize() == 0 { - TransactionType::AccessList - } else if transaction_type.as_usize() == 1 { - TransactionType::Eip1559 - } else { - TransactionType::Legacy - } - } - None => TransactionType::Legacy, + Some(transaction_type) => match transaction_type.into() { + 0 => "legacy".to_string(), + 1 => "access_list".to_string(), + 2 => "eip_1559".to_string(), + 3 => "blob".to_string(), + _ => "legacy".to_string(), + }, + None => "legacy".to_string(), }; - let access_list: Vec<(String, Vec)> = + let access_list: Vec<(Address, Vec)> = match transaction.access_list.to_owned() { Some(access_list_items) => { - let mut access_list: Vec<(String, Vec)> = + let mut access_list: Vec<(Address, Vec)> = Vec::new(); for item in access_list_items.0 { - let keys: Vec = item - .storage_keys - .into_iter() - .map(format_hash) - .collect(); - - access_list - .push((format_address(item.address), keys)) + access_list.push((item.address, item.storage_keys)) } access_list @@ -107,70 +96,82 @@ impl DatabaseTransaction { None => Vec::new(), }; + let status = if receipt.status() { + Some("success".to_string()) + } else { + Some("failure".to_string()) + }; + + let effective_gas_price = match receipt.effective_gas_price { + 0 => match transaction.gas_price { + Some(gas_price) => U256::from(gas_price), + None => match base_fee_per_gas { + Some(base_fee_per_gas) => { + let max_priority_fee_per_gas = transaction + .max_priority_fee_per_gas + .map(U256::from) + .unwrap_or_default(); + + U256::from(base_fee_per_gas) + + max_priority_fee_per_gas + } + None => U256::ZERO, + }, + }, + _ => U256::from(receipt.effective_gas_price), + }; + Self { access_list, - base_fee_per_gas: None, - block_hash: format_hash(transaction.block_hash.unwrap()), - block_number: transaction.block_number.unwrap().as_usize() - as u32, + base_fee_per_gas, + block_hash: transaction.block_hash.unwrap(), + block_number: transaction.block_number.unwrap() as u32, chain, - contract_created: None, - cumulative_gas_used: None, - effective_gas_price: None, - from: format_address(transaction.from), - gas: transaction.gas.as_usize() as u32, - gas_price: transaction.gas_price, - gas_used: None, - hash: format_hash(transaction.hash), - input: format_bytes(&transaction.input), - max_fee_per_gas: transaction.max_fee_per_gas, - max_priority_fee_per_gas: transaction.max_priority_fee_per_gas, - method: format!( - "0x{}", - hex::encode(byte4_from_input(&format_bytes( - &transaction.input - ))) - ), - nonce: transaction.nonce.as_usize() as u32, - status: None, + contract_created: receipt.contract_address, + cumulative_gas_used: Some(match &receipt.inner { + alloy::consensus::ReceiptEnvelope::Legacy(r) => { + r.receipt.cumulative_gas_used + } + alloy::consensus::ReceiptEnvelope::Eip2930(r) => { + r.receipt.cumulative_gas_used + } + alloy::consensus::ReceiptEnvelope::Eip1559(r) => { + r.receipt.cumulative_gas_used + } + alloy::consensus::ReceiptEnvelope::Eip4844(r) => { + r.receipt.cumulative_gas_used + } + _ => 0, + } as u32), + effective_gas_price: Some(effective_gas_price), + from: transaction.from, + gas: transaction.gas as u32, + gas_price: transaction.gas_price.map(|p| U256::from(p)), + gas_used: Some(receipt.gas_used as u32), + hash: transaction.hash, + input: transaction.input.clone(), + max_fee_per_gas: transaction + .max_fee_per_gas + .map(|p| U256::from(p)), + max_priority_fee_per_gas: transaction + .max_priority_fee_per_gas + .map(|p| U256::from(p)), + method: { + let input_bytes = transaction.input.as_ref(); + if input_bytes.len() >= 4 { + format!("0x{}", hex::encode(&input_bytes[..4])) + } else { + String::from("0x00000000") + } + }, + nonce: transaction.nonce as u32, + status, timestamp, to, - transaction_index: transaction - .transaction_index - .unwrap() - .as_u64() as u16, - transaction_type, + transaction_index: transaction.transaction_index.unwrap() + as u16, + transaction_type: transaction_type_str, value: transaction.value, } } - - pub fn add_receipt_data( - &mut self, - base_fee_per_gas: Option, - receipt: &TransactionReceipt, - ) { - let gas_used = receipt.gas_used.unwrap(); - - let status = match receipt.status { - Some(status) => { - if status.as_usize() == 0 { - TransactionStatus::Failure - } else if status.as_usize() == 1 { - TransactionStatus::Success - } else { - TransactionStatus::Unknown - } - } - None => TransactionStatus::Unknown, - }; - - self.base_fee_per_gas = base_fee_per_gas; - self.contract_created = - receipt.contract_address.map(format_address); - self.cumulative_gas_used = - Some(receipt.cumulative_gas_used.as_usize() as u32); - self.effective_gas_price = receipt.effective_gas_price; - self.gas_used = Some(gas_used.as_usize() as u32); - self.status = Some(status) - } } diff --git a/src/db/models/withdrawal.rs b/src/db/models/withdrawal.rs index be8b37f..a82c999 100644 --- a/src/db/models/withdrawal.rs +++ b/src/db/models/withdrawal.rs @@ -1,22 +1,22 @@ +use alloy::primitives::{Address, U256}; +use alloy::rpc::types::Withdrawal; use clickhouse::Row; -use ethers::types::Withdrawal; -use primitive_types::U256; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use crate::utils::format::{format_address, SerU256}; +use crate::utils::format::SerU256; #[serde_as] #[derive(Debug, Clone, Row, Serialize, Deserialize)] pub struct DatabaseWithdrawal { - pub address: String, + pub address: Address, #[serde_as(as = "SerU256")] pub amount: U256, pub block_number: u32, pub chain: u64, pub timestamp: u32, - pub validator_index: u32, - pub withdrawal_index: u32, + pub validator_index: u64, + pub withdrawal_index: u64, } impl DatabaseWithdrawal { @@ -27,13 +27,13 @@ impl DatabaseWithdrawal { timestamp: u32, ) -> Self { Self { - address: format_address(withdrawal.address), - amount: withdrawal.amount, + address: withdrawal.address, + amount: U256::from(withdrawal.amount), block_number, chain, timestamp, - validator_index: withdrawal.validator_index.as_usize() as u32, - withdrawal_index: withdrawal.index.as_usize() as u32, + validator_index: withdrawal.index, + withdrawal_index: withdrawal.index, } } } diff --git a/src/lib.rs b/src/lib.rs index 31af9a9..6cd0a2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -pub mod chains; pub mod configs; pub mod db; pub mod rpc; diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index c802dac..bf2a2d3 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -1,92 +1,78 @@ use crate::{ - chains::Chain, configs::Config, db::{ models::{ - block::DatabaseBlock, - contract::DatabaseContract, + block::DatabaseBlock, contract::DatabaseContract, + dex_trade::DatabaseDexTrade, erc1155_transfer::DatabaseERC1155Transfer, erc20_transfer::DatabaseERC20Transfer, - erc721_transfer::DatabaseERC721Transfer, - log::DatabaseLog, - trace::{DatabaseTrace, TraceType}, - transaction::DatabaseTransaction, + erc721_transfer::DatabaseERC721Transfer, log::DatabaseLog, + trace::DatabaseTrace, transaction::DatabaseTransaction, withdrawal::DatabaseWithdrawal, }, BlockFetchedData, Database, }, utils::{ + dex_factories::DexRouters, events::{ + BALANCER_SWAP_EVENT_SIGNATURE, + CURVE_TOKEN_EXCHANGE_EVENT_SIGNATURE, + CURVE_TOKEN_EXCHANGE_UNDERLYING_EVENT_SIGNATURE, + DODO_SWAP_EVENT_SIGNATURE, ERC1155_TRANSFER_BATCH_EVENT_SIGNATURE, ERC1155_TRANSFER_SINGLE_EVENT_SIGNATURE, - TRANSFER_EVENTS_SIGNATURE, + KYBER_SWAPPED_EVENT_SIGNATURE, + MAVERICK_SWAP_FILLED_EVENT_SIGNATURE, + TRADERJOE_LB_SWAP_EVENT_SIGNATURE, TRANSFER_EVENTS_SIGNATURE, + UNISWAP_V2_SWAP_EVENT_SIGNATURE, + UNISWAP_V3_SWAP_EVENT_SIGNATURE, WOOFI_SWAP_EVENT_SIGNATURE, }, - format::{decode_bytes, format_hash}, }, }; -use ethabi::ParamType; -use ethers::{ - abi::ethabi, - types::{Block, Trace, Transaction, TransactionReceipt, TxHash}, +use alloy::primitives::{Address, B256}; +use alloy::providers::{ + Provider, ProviderBuilder, RootProvider, WsConnect, }; -use primitive_types::U256; - -use jsonrpsee::{ - core::{ - client::{ClientT, Subscription, SubscriptionClientT}, - rpc_params, - }, - tracing::debug, -}; -use jsonrpsee_http_client::{ - transport::HttpBackend, HttpClient, HttpClientBuilder, +use alloy::rpc::types::{ + BlockNumberOrTag, BlockTransactions, Transaction, TransactionReceipt, }; -use jsonrpsee_ws_client::{WsClient, WsClientBuilder}; - -use log::{info, warn}; +use alloy::transports::http::Http; +use alloy_rpc_types_trace::parity::LocalizedTransactionTrace as Trace; +use futures::StreamExt; +use log::{debug, error, info, warn}; use rand::seq::SliceRandom; -use std::{collections::HashMap, time::Duration}; -use tokio::time::sleep; - -use serde_json::Error; +use reqwest::Client; +use std::collections::HashMap; +use url::Url; -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct Rpc { - pub chain: Chain, - pub clients: Vec>, + pub chain_id: u64, + pub clients: Vec>>, pub clients_urls: Vec, pub ws_url: Option, pub traces: bool, + pub supports_blocks_receipts: bool, + pub fetch_uncles: bool, + pub dex_routers: DexRouters, } impl Rpc { pub async fn new(config: &Config) -> Self { info!("Starting rpc service"); - let timeout = Duration::from_secs(60); - let mut clients = Vec::new(); let mut clients_urls = Vec::new(); for rpc in config.rpcs.iter() { - let client = HttpClientBuilder::default() - .max_concurrent_requests(100000) - .request_timeout(timeout) - .build(rpc) - .unwrap(); - - let client_id = - client.request("eth_chainId", rpc_params![]).await; - - match client_id { - Ok(value) => { - let chain_id: U256 = - match serde_json::from_value(value) { - Ok(value) => value, - Err(_) => continue, - }; - - if chain_id.as_u64() != config.chain.id { + let url = Url::parse(rpc).expect("Invalid RPC URL"); + let client = ProviderBuilder::new().on_http(url); + + let chain_id = client.get_chain_id().await; + + match chain_id { + Ok(id) => { + if id != config.chain_id { continue; } @@ -101,38 +87,63 @@ impl Rpc { panic!("No valid rpc client found"); } - Self { - chain: config.chain.clone(), + let mut rpc = Self { + chain_id: config.chain_id, clients, clients_urls, ws_url: config.ws_url.clone(), traces: config.traces, + supports_blocks_receipts: false, + fetch_uncles: config.fetch_uncles, + dex_routers: DexRouters::new(), + }; + + rpc.detect_capabilities().await; + + rpc + } + + async fn detect_capabilities(&mut self) { + info!("Detecting RPC capabilities for chain {}", self.chain_id); + let start = std::time::Instant::now(); + + let client = self.get_client(); + let latest_block = client.get_block_number().await; + + if let Ok(block_number) = latest_block { + let receipts = client + .raw_request::<_, Vec>( + "eth_getBlockReceipts".into(), + [format!("0x{:x}", block_number)], + ) + .await; + + self.supports_blocks_receipts = receipts.is_ok(); + + let elapsed = start.elapsed(); + info!( + "RPC capability detection completed in {:.2}s: eth_getBlockReceipts={}", + elapsed.as_secs_f64(), + self.supports_blocks_receipts + ); + } else { + warn!("Failed to detect RPC capabilities: unable to get latest block"); } } pub async fn get_last_block(&self) -> u32 { + debug!("Fetching latest block number for chain {}", self.chain_id); let client = self.get_client(); - let last_block = - client.request("eth_blockNumber", rpc_params![]).await; - - match last_block { - Ok(value) => { - let block_number: U256 = serde_json::from_value(value) - .expect( - "Unable to deserialize eth_blockNumber response", - ); - - block_number.as_usize() as u32 - } - Err(_) => 0, - } + let block = client.get_block_number().await.unwrap(); + let block_number = block.try_into().unwrap(); + debug!("Latest block: {}", block_number); + block_number } pub async fn fetch_block( &self, block_number: &u32, - chain: &Chain, ) -> Option<( Vec, Vec, @@ -143,6 +154,7 @@ impl Rpc { Vec, Vec, Vec, + Vec, )> { let block_data = self.get_block(block_number).await; @@ -158,32 +170,33 @@ impl Rpc { match block_data { Some(( db_block, - mut db_transactions, + raw_transactions, db_withdrawals, mut block_uncles, )) => { - let total_block_transactions = db_transactions.len(); + let total_block_transactions = raw_transactions.len(); // Make sure all the transactions are correctly formatted. if db_block.transactions != total_block_transactions as u16 { warn!( - "Missing {} transactions for block {}.", + "Missing {} transactions for block {}. Actual: {}", db_block.transactions - total_block_transactions as u16, - db_block.number + db_block.number, + total_block_transactions ); return None; } - let mut db_receipts: HashMap = - HashMap::new(); + let mut db_receipts: HashMap = + HashMap::with_capacity(total_block_transactions); let mut db_logs: Vec = Vec::new(); - let mut contracts_map: HashMap = + let mut contracts_map: HashMap = HashMap::new(); - if chain.supports_blocks_receipts { + if self.supports_blocks_receipts { let receipts_data = self .get_block_receipts( block_number, @@ -195,26 +208,26 @@ impl Rpc { Some((receipts, mut logs, contracts)) => { for receipt in receipts { db_receipts.insert( - format_hash(receipt.transaction_hash), + receipt.transaction_hash, receipt, ); } db_logs.append(&mut logs); for contract in contracts { contracts_map.insert( - contract.contract_address.clone(), - contract.clone(), + contract.contract_address, + contract, ); } } None => return None, } } else { - for transaction in db_transactions.iter() { + for transaction in raw_transactions.iter() { let receipt_data = self .get_transaction_receipt( - transaction.hash.clone(), - transaction.timestamp, + transaction.hash, + db_block.timestamp, block_number, ) .await; @@ -222,20 +235,15 @@ impl Rpc { match receipt_data { Some((receipt, mut logs, contract)) => { db_receipts.insert( - format_hash(receipt.transaction_hash), + receipt.transaction_hash, receipt, ); db_logs.append(&mut logs); - match contract { - Some(contract) => { - contracts_map.insert( - contract - .contract_address - .clone(), - contract.clone(), - ); - } - None => continue, + if let Some(contract) = contract { + contracts_map.insert( + contract.contract_address, + contract, + ); } } None => continue, @@ -253,16 +261,23 @@ impl Rpc { return None; } - // TODO: add receipt data to transactions - for transaction in db_transactions.iter_mut() { + // Re-create db_transactions with receipt data + let mut db_transactions = Vec::new(); + + for transaction in raw_transactions { let receipt = db_receipts - .get(&transaction.hash.clone()) + .get(&transaction.hash) .expect("unable to get receipt for transaction"); - transaction.add_receipt_data( - db_block.base_fee_per_gas, + let db_transaction = DatabaseTransaction::from_rpc( + &transaction, receipt, + self.chain_id, + db_block.timestamp, + db_block.base_fee_per_gas, ); + + db_transactions.push(db_transaction) } let mut db_blocks: Vec = Vec::new(); @@ -276,32 +291,28 @@ impl Rpc { // Insert contracts created through the traces let create_traces: Vec<&DatabaseTrace> = traces .iter() - .filter(|trace| trace.action_type == TraceType::Create) + .filter(|trace| trace.action_type == "create") .collect(); for trace in create_traces { - let contract_address = match &trace.address { + let contract_address = match trace.address { Some(contract_address) => contract_address, None => continue, }; - if contracts_map.contains_key(contract_address) { + if contracts_map.contains_key(&contract_address) { continue; } let contract = DatabaseContract { block_number: trace.block_number, - contract_address: contract_address.to_string(), - chain: self.chain.id, - creator: trace.from.clone().unwrap(), - transaction_hash: trace - .transaction_hash - .clone() - .unwrap(), + contract_address, + chain: self.chain_id, + creator: trace.from.unwrap(), + transaction_hash: trace.transaction_hash.unwrap(), }; - contracts_map - .insert(contract_address.to_string(), contract); + contracts_map.insert(contract_address, contract); } let mut db_erc20_transfers: Vec = @@ -316,105 +327,356 @@ impl Rpc { for log in db_logs.iter_mut() { // Check the first topic matches the erc20, erc721, erc1155 or a swap signatures - let topic0 = log.topic0.clone(); + let topic0 = log.topic0; - if topic0 == TRANSFER_EVENTS_SIGNATURE { + if topic0 + == Some(TRANSFER_EVENTS_SIGNATURE.parse().unwrap()) + { // Check if it is a erc20 or a erc721 based on the number of logs // erc721 token transfer events have 3 indexed values. if log.topic3.is_some() { let erc721 = - DatabaseERC721Transfer::from_rpc(log); + DatabaseERC721Transfer::from_log(log); - db_erc721_transfers.push(erc721) + if let Some(erc721) = erc721 { + db_erc721_transfers.push(erc721) + } } else if log.topic1.is_some() && log.topic2.is_some() { // erc20 token transfer events have 2 indexed values. let erc20 = - DatabaseERC20Transfer::from_rpc(log); + DatabaseERC20Transfer::from_log(log); - db_erc20_transfers.push(erc20) + if let Some(erc20) = erc20 { + db_erc20_transfers.push(erc20) + } } } - if topic0 == ERC1155_TRANSFER_SINGLE_EVENT_SIGNATURE + if topic0 + == Some( + ERC1155_TRANSFER_SINGLE_EVENT_SIGNATURE + .parse() + .unwrap(), + ) && log.topic1.is_some() && log.topic2.is_some() && log.topic3.is_some() { - let log_data = decode_bytes(log.data.clone()); + let erc1155_transfer = + DatabaseERC1155Transfer::from_log(log); + + if let Some(erc1155_transfer) = erc1155_transfer { + db_erc1155_transfers.push(erc1155_transfer); + } + } - let transfer_values = ethabi::decode( - &[ParamType::Uint(256), ParamType::Uint(256)], - &log_data[..], + if topic0 + == Some( + ERC1155_TRANSFER_BATCH_EVENT_SIGNATURE + .parse() + .unwrap(), ) - .unwrap(); + { + let erc1155_transfer = + DatabaseERC1155Transfer::from_log(log); - let id = transfer_values[0] - .clone() - .into_uint() - .unwrap(); + if let Some(erc1155_transfer) = erc1155_transfer { + db_erc1155_transfers.push(erc1155_transfer); + } + } + } - let amount = transfer_values[1] - .clone() - .into_uint() - .unwrap(); + // Decode DEX trades with automatic DEX detection + let mut db_dex_trades: Vec = Vec::new(); - let erc1155_transfer = - DatabaseERC1155Transfer::from_single_rpc( - log, id, amount, - ); + // Create mapping of transaction_hash -> to_address (router) for DEX detection + let mut tx_routers: HashMap = + HashMap::new(); + for tx in db_transactions.iter() { + tx_routers.insert(tx.hash, tx.to); + } + + // Convert DatabaseLog to alloy Log for processing + for log in db_logs.iter() { + let topic0 = log.topic0; + + // Get router address for this transaction to detect DEX + let router = tx_routers.get(&log.transaction_hash); + + // Detect DEX name from router address + let router_dex_name = if let Some(router_addr) = router { + self.dex_routers + .get_dex_from_router( + self.chain_id, + router_addr, + ) + .map(|info| info.display_name()) + } else { + None + }; - db_erc1155_transfers.push(erc1155_transfer); + // Reconstruct alloy Log from DatabaseLog + let alloy_log = alloy::rpc::types::Log { + inner: alloy::primitives::Log { + address: log.address, + data: alloy::primitives::LogData::new( + vec![ + log.topic0.unwrap_or_default(), + log.topic1.unwrap_or_default(), + log.topic2.unwrap_or_default(), + log.topic3.unwrap_or_default(), + ], + log.data.clone(), + ) + .unwrap(), + }, + block_hash: None, + block_number: Some(log.block_number as u64), + block_timestamp: None, + transaction_hash: Some(log.transaction_hash), + transaction_index: None, + log_index: Some(log.log_index as u64), + removed: false, + }; + + // Uniswap V2-style Swap (PancakeSwap, SushiSwap, QuickSwap, Solidly forks, etc.) + if topic0 + == Some( + UNISWAP_V2_SWAP_EVENT_SIGNATURE + .parse() + .unwrap(), + ) + { + // For V2 swaps, use chain-specific default DEX when router not detected + // This properly labels Solidly forks (Velodrome, Aerodrome, Thena, etc.) + let v2_dex_name = router_dex_name.clone().unwrap_or_else(|| { + self.dex_routers.get_default_v2_dex(self.chain_id).to_string() + }); + if let Some(trade) = + DatabaseDexTrade::from_uniswap_v2_swap( + &alloy_log, + self.chain_id, + log.block_number, + log.timestamp, + log.transaction_hash, + log.log_index, + v2_dex_name, + ) + { + db_dex_trades.push(trade); + } } - if topic0 == ERC1155_TRANSFER_BATCH_EVENT_SIGNATURE - && log.topic1.is_some() - && log.topic2.is_some() - && log.topic3.is_some() + // Uniswap V3-style Swap (PancakeSwap V3, Algebra forks, etc.) + if topic0 + == Some( + UNISWAP_V3_SWAP_EVENT_SIGNATURE + .parse() + .unwrap(), + ) { - let log_data = decode_bytes(log.data.clone()); - - let transfer_values = ethabi::decode( - &[ - ParamType::Array(Box::new( - ParamType::Uint(256), - )), - ParamType::Array(Box::new( - ParamType::Uint(256), - )), - ], - &log_data[..], + // For V3 swaps, use chain-specific default DEX when router not detected + let v3_dex_name = router_dex_name.clone().unwrap_or_else(|| { + self.dex_routers.get_default_v3_dex(self.chain_id).to_string() + }); + if let Some(trade) = + DatabaseDexTrade::from_uniswap_v3_swap( + &alloy_log, + self.chain_id, + log.block_number, + log.timestamp, + log.transaction_hash, + log.log_index, + v3_dex_name, + ) + { + db_dex_trades.push(trade); + } + } + + // Curve TokenExchange + if topic0 + == Some( + CURVE_TOKEN_EXCHANGE_EVENT_SIGNATURE + .parse() + .unwrap(), ) - .unwrap(); - - let ids: Vec = transfer_values[0] - .clone() - .into_array() - .unwrap() - .iter() - .map(|token| { - token.clone().into_uint().unwrap() - }) - .collect(); - - let amounts: Vec = transfer_values[1] - .clone() - .into_array() - .unwrap() - .iter() - .map(|token| { - token.clone().into_uint().unwrap() - }) - .collect(); + { + if let Some(trade) = + DatabaseDexTrade::from_curve_token_exchange( + &alloy_log, + self.chain_id, + log.block_number, + log.timestamp, + log.transaction_hash, + log.log_index, + ) + { + db_dex_trades.push(trade); + } + } - let erc1155_transfer = - DatabaseERC1155Transfer::from_batch_rpc( - log, ids, amounts, - ); + // Balancer Swap + if topic0 + == Some( + BALANCER_SWAP_EVENT_SIGNATURE.parse().unwrap(), + ) + { + // Balancer has its own unique event, so fallback is always Balancer + let balancer_dex_name = router_dex_name.clone() + .unwrap_or_else(|| "Balancer V2".to_string()); + if let Some(trade) = + DatabaseDexTrade::from_balancer_swap( + &alloy_log, + self.chain_id, + log.block_number, + log.timestamp, + log.transaction_hash, + log.log_index, + balancer_dex_name, + ) + { + db_dex_trades.push(trade); + } + } + + // DODO Swap + if topic0 + == Some(DODO_SWAP_EVENT_SIGNATURE.parse().unwrap()) + { + let dodo_dex_name = router_dex_name.clone() + .unwrap_or_else(|| "DODO".to_string()); + if let Some(trade) = + DatabaseDexTrade::from_dodo_swap( + &alloy_log, + self.chain_id, + log.block_number, + log.timestamp, + log.transaction_hash, + log.log_index, + dodo_dex_name, + ) + { + db_dex_trades.push(trade); + } + } + + // Kyber Swapped + if topic0 + == Some( + KYBER_SWAPPED_EVENT_SIGNATURE.parse().unwrap(), + ) + { + let kyber_dex_name = router_dex_name.clone() + .unwrap_or_else(|| "Kyber".to_string()); + if let Some(trade) = + DatabaseDexTrade::from_kyber_swapped( + &alloy_log, + self.chain_id, + log.block_number, + log.timestamp, + log.transaction_hash, + log.log_index, + kyber_dex_name, + ) + { + db_dex_trades.push(trade); + } + } + + // Maverick SwapFilled + if topic0 + == Some( + MAVERICK_SWAP_FILLED_EVENT_SIGNATURE + .parse() + .unwrap(), + ) + { + let maverick_dex_name = router_dex_name.clone() + .unwrap_or_else(|| "Maverick".to_string()); + if let Some(trade) = + DatabaseDexTrade::from_maverick_swap_filled( + &alloy_log, + self.chain_id, + log.block_number, + log.timestamp, + log.transaction_hash, + log.log_index, + maverick_dex_name, + ) + { + db_dex_trades.push(trade); + } + } + + // Curve TokenExchangeUnderlying (meta pools) + if topic0 + == Some( + CURVE_TOKEN_EXCHANGE_UNDERLYING_EVENT_SIGNATURE + .parse() + .unwrap(), + ) + { + if let Some(trade) = + DatabaseDexTrade::from_curve_token_exchange_underlying( + &alloy_log, + self.chain_id, + log.block_number, + log.timestamp, + log.transaction_hash, + log.log_index, + ) + { + db_dex_trades.push(trade); + } + } + + // TraderJoe V2.1 LB Swap + if topic0 + == Some( + TRADERJOE_LB_SWAP_EVENT_SIGNATURE + .parse() + .unwrap(), + ) + { + let traderjoe_dex_name = router_dex_name.clone() + .unwrap_or_else(|| "TraderJoe".to_string()); + if let Some(trade) = + DatabaseDexTrade::from_traderjoe_lb_swap( + &alloy_log, + self.chain_id, + log.block_number, + log.timestamp, + log.transaction_hash, + log.log_index, + traderjoe_dex_name, + ) + { + db_dex_trades.push(trade); + } + } - db_erc1155_transfers.push(erc1155_transfer); + // WooFi WooSwap + if topic0 + == Some( + WOOFI_SWAP_EVENT_SIGNATURE.parse().unwrap(), + ) + { + if let Some(trade) = + DatabaseDexTrade::from_woofi_swap( + &alloy_log, + self.chain_id, + log.block_number, + log.timestamp, + log.transaction_hash, + log.log_index, + ) + { + db_dex_trades.push(trade); + } } } @@ -443,6 +705,7 @@ impl Rpc { db_erc20_transfers, db_erc721_transfers, db_erc1155_transfers, + db_dex_trades, )) } None => None, @@ -452,229 +715,236 @@ impl Rpc { pub async fn listen_blocks(&self, db: &Database) { info!("Starting new blocks listener."); - let client = self.get_ws_client().await; + let ws_url = self.ws_url.clone().unwrap(); + let ws_connect = WsConnect::new(ws_url); + let client = ProviderBuilder::new() + .on_ws(ws_connect) + .await + .expect("unable to connect to websocket"); - let client_id = client.request("eth_chainId", rpc_params![]).await; + let chain_id = client + .get_chain_id() + .await + .expect("unable to get chain id from websocket"); - match client_id { - Ok(value) => { - let chain_id: U256 = match serde_json::from_value(value) { - Ok(value) => value, - Err(_) => { - panic!("unable to get chain id from websocket") - } - }; + if chain_id != self.chain_id { + panic!("websocket chain id doesn't match with configured chain id") + } - if chain_id.as_u64() != self.chain.id { - panic!("websocket chain id doesn't match with configured chain id") - } - } - Err(_) => panic!("unable to access websocket"), + // Detect capabilities on websocket connection + let latest_block = client.get_block_number().await; + let mut ws_supports_block_receipts = false; + + if let Ok(block_number) = latest_block { + let receipts = client + .raw_request::<_, Vec>( + "eth_getBlockReceipts".into(), + [format!("0x{:x}", block_number)], + ) + .await; + + ws_supports_block_receipts = receipts.is_ok(); + info!( + "Websocket capability detection: eth_getBlockReceipts={}", + ws_supports_block_receipts + ); + } else { + warn!("Failed to detect websocket capabilities: unable to get latest block"); } - let mut subscription: Subscription> = client - .subscribe( - "eth_subscribe", - rpc_params!["newHeads"], - "eth_unsubscribe", - ) + let subscription = client + .subscribe_blocks() .await .expect("unable to start block listener"); + let mut stream = subscription.into_stream(); - while let Some(block) = subscription.next().await { - if block.is_err() { - continue; - } + while let Some(block) = stream.next().await { tokio::spawn({ let rpc = self.clone(); let db = db.clone(); - let block = block.unwrap().clone(); + let block = block.clone(); + let supports_receipts = ws_supports_block_receipts; async move { - let block_number = - block.number.unwrap().as_usize() as u32; + let block_number = block.header.number.unwrap() as u32; - info!("New head found {}.", block_number.clone()); + info!("New head found {}.", block_number); - // Some chains require a small delay between receiving the head and fetching the block - // to allow the chain and nodes propagate and execute the block data. + // Use websocket capability detection to optimize trace fetching + let mut rpc_with_ws_capability = rpc.clone(); + rpc_with_ws_capability.supports_blocks_receipts = + supports_receipts; - // The list of chains to add delay should be added manually and tested - // Right now this is tested for ETH (1) and BSC (56) - // These values can change depending on network load + // Retry logic for new heads - RPC may not have synced yet + let max_retries = 10; + let mut retry_delay = + std::time::Duration::from_millis(100); - // ETH requires 300ms - if rpc.chain.id == 1 { - sleep(Duration::from_millis(300)).await; - } + for attempt in 1..=max_retries { + // Small delay before first attempt to let RPC sync + if attempt == 1 { + tokio::time::sleep( + std::time::Duration::from_millis(50), + ) + .await; + } - // BSC requires 4s - if rpc.chain.id == 56 { - sleep(Duration::from_secs(4)).await; - } + let block_data = rpc_with_ws_capability + .fetch_block(&block_number) + .await; - let block_data = - rpc.fetch_block(&block_number, &rpc.chain).await; - - if let Some(( - blocks, - transactions, - logs, - contracts, - traces, - withdrawals, - erc20_transfers, - erc721_transfers, - erc1155_transfers, - )) = block_data - { - let fetched_data = BlockFetchedData { - blocks, - contracts, - logs, - traces, - transactions, - withdrawals, - erc20_transfers, - erc721_transfers, - erc1155_transfers, - }; - - db.store_data(&fetched_data).await; + match block_data { + Some(( + blocks, + transactions, + logs, + contracts, + traces, + withdrawals, + erc20_transfers, + erc721_transfers, + erc1155_transfers, + dex_trades, + )) => { + let fetched_data = BlockFetchedData { + blocks, + contracts, + logs, + traces, + transactions, + withdrawals, + erc20_transfers, + erc721_transfers, + erc1155_transfers, + dex_trades, + }; + + db.store_data(&fetched_data).await; + break; + } + None => { + if attempt < max_retries { + debug!( + "Failed to fetch new head {} (attempt {}/{}), retrying in {:?}", + block_number, attempt, max_retries, retry_delay + ); + tokio::time::sleep(retry_delay).await; + retry_delay *= 2; // Exponential backoff + } else { + error!( + "Failed to fetch new head {} after {} attempts, block will be picked up by indexer later", + block_number, max_retries + ); + } + } + } } } }); } } - fn get_client(&self) -> &HttpClient { + fn get_client(&self) -> &RootProvider> { let client = self.clients.choose(&mut rand::thread_rng()).unwrap(); client } - async fn get_ws_client(&self) -> WsClient { - let url = self.ws_url.clone().unwrap(); - - let client_wss: WsClient = - WsClientBuilder::default().build(url).await.unwrap(); - - client_wss - } - - async fn get_block( + pub async fn get_block( &self, block_number: &u32, ) -> Option<( DatabaseBlock, - Vec, + Vec, Vec, Vec, )> { let client = self.get_client(); - - let raw_block = client - .request( - "eth_getBlockByNumber", - rpc_params![format!("0x{:x}", block_number), true], + let block = client + .get_block_by_number( + BlockNumberOrTag::Number(*block_number as u64), + true, ) .await; - match raw_block { - Ok(value) => { - let block: Result, Error> = - serde_json::from_value(value); - - match block { - Ok(block) => { - let db_block = DatabaseBlock::from_rpc( - &block, - self.chain.id, - false, - ); + match block { + Ok(block) => match block { + Some(block) => { + let is_uncle = false; + let db_block = DatabaseBlock::from_rpc( + &block, + self.chain_id, + is_uncle, + ); - let mut db_transactions = Vec::new(); + let mut db_transactions: Vec = Vec::new(); - for transaction in block.transactions.iter() { - let db_transaction = - DatabaseTransaction::from_rpc( - transaction, - self.chain.id, - db_block.timestamp, - ); + if let BlockTransactions::Full(txs) = + &block.transactions + { + db_transactions.extend(txs.iter().cloned()); + } - db_transactions.push(db_transaction) - } + let mut db_withdrawals: Vec = + Vec::new(); - let mut db_withdrawals = Vec::new(); - - if block.withdrawals.is_some() { - for withdrawal in - block.withdrawals.unwrap().iter() - { - let db_withdrawal = - DatabaseWithdrawal::from_rpc( - withdrawal, - self.chain.id, - db_block.number, - db_block.timestamp, - ); + if let Some(withdrawals) = &block.withdrawals { + for withdrawal in withdrawals { + let db_withdrawal = + DatabaseWithdrawal::from_rpc( + withdrawal, + self.chain_id, + db_block.number, + db_block.timestamp, + ); - db_withdrawals.push(db_withdrawal) - } + db_withdrawals.push(db_withdrawal) } - - let mut block_uncles = Vec::new(); - - for (i, _) in db_block.uncles.iter().enumerate() { - let raw_uncle = client - .request( - "eth_getUncleByBlockNumberAndIndex", - rpc_params![ - format!("0x{:x}", db_block.number), - format!("0x{:x}", i) - ], + } + let mut block_uncles = Vec::new(); + + if self.fetch_uncles { + for (i, _) in block.uncles.iter().enumerate() { + let uncle = client + .get_uncle( + alloy::rpc::types::BlockId::Number( + BlockNumberOrTag::Number( + *block_number as u64, + ), + ), + i as u64, ) .await; - match raw_uncle { - Ok(value) => { - let block: Result< - Block, - Error, - > = serde_json::from_value(value); - - match block { - Ok(block) => { - let db_block = - DatabaseBlock::from_rpc( - &block, - self.chain.id, - true, - ); - - block_uncles.push(db_block) - } - Err(err) => { - println!("{}", err) - } - } - } - Err(err) => { - println!("{}", err) - } + + if let Ok(Some(block)) = uncle { + let db_block = DatabaseBlock::from_rpc( + &block, + self.chain_id, + true, + ); + block_uncles.push(db_block) } } - - Some(( - db_block, - db_transactions, - db_withdrawals, - block_uncles, - )) + } else if !block.uncles.is_empty() { + debug!( + "Skipping {} uncle blocks for block {} (fetch_uncles=false)", + block.uncles.len(), + block_number + ); } - Err(_) => None, + + Some(( + db_block, + db_transactions, + db_withdrawals, + block_uncles, + )) } + None => None, + }, + Err(e) => { + error!("Error fetching block: {:?}", e); + None } - Err(_) => None, } } @@ -684,35 +954,27 @@ impl Rpc { ) -> Vec { let client = self.get_client(); - let raw_block = client - .request( - "trace_block", - rpc_params![format!("0x{:x}", block_number)], + // trace_block is not yet in standard Alloy provider trait in 0.1? + // We use raw request + let traces: Result, _> = client + .raw_request( + "trace_block".into(), + vec![format!("0x{:x}", block_number)], ) .await; - match raw_block { - Ok(value) => { - let traces: Result, Error> = - serde_json::from_value(value); - - match traces { - Ok(traces) => { - let mut db_traces = Vec::new(); - - for trace in traces.iter() { - let db_trace = DatabaseTrace::from_rpc( - trace, - self.chain.id, - ); + match traces { + Ok(traces) => { + let mut db_traces = Vec::new(); - db_traces.push(db_trace) - } + for trace in traces.iter() { + let db_trace = + DatabaseTrace::from_rpc(trace, self.chain_id); - db_traces - } - Err(_) => Vec::new(), + db_traces.push(db_trace) } + + db_traces } Err(_) => Vec::new(), } @@ -720,7 +982,7 @@ impl Rpc { async fn get_transaction_receipt( &self, - transaction: String, + transaction: B256, transaction_timestamp: u32, block_number: &u32, ) -> Option<( @@ -730,59 +992,36 @@ impl Rpc { )> { let client = self.get_client(); - let raw_receipt = client - .request("eth_getTransactionReceipt", rpc_params![transaction]) - .await; - - match raw_receipt { - Ok(value) => { - let receipt: Result = - serde_json::from_value(value); + let receipt = client.get_transaction_receipt(transaction).await; - match receipt { - Ok(receipt) => { - let mut db_transaction_logs: Vec = - Vec::new(); + match receipt { + Ok(Some(receipt)) => { + let mut db_transaction_logs: Vec = Vec::new(); - let status: bool = match receipt.status { - None => true, - Some(status) => { - let status_number = status.as_u64() as i64; + let status = receipt.status(); - status_number != 0 - } - }; - - let mut db_contract: Option = - None; - - if status { - db_contract = - receipt.contract_address.map(|_| { - DatabaseContract::from_rpc( - &receipt, - self.chain.id, - ) - }); - } + let mut db_contract: Option = None; - for log in receipt.logs.iter() { - let db_log = DatabaseLog::from_rpc( - log, - self.chain.id, - transaction_timestamp, - block_number, - ); + if status { + db_contract = receipt.contract_address.map(|_| { + DatabaseContract::from_rpc(&receipt, self.chain_id) + }); + } - db_transaction_logs.push(db_log) - } + for log in receipt.inner.logs() { + let db_log = DatabaseLog::from_rpc( + log, + self.chain_id, + transaction_timestamp, + block_number, + ); - Some((receipt, db_transaction_logs, db_contract)) - } - Err(_) => None, + db_transaction_logs.push(db_log) } + + Some((receipt, db_transaction_logs, db_contract)) } - Err(_) => None, + _ => None, } } @@ -797,67 +1036,42 @@ impl Rpc { )> { let client = self.get_client(); - let raw_receipts = client - .request( - "eth_getBlockReceipts", - rpc_params![format!("0x{:x}", block_number)], + // eth_getBlockReceipts might not be standard, use raw request + let receipts: Result, _> = client + .raw_request( + "eth_getBlockReceipts".into(), + vec![format!("0x{:x}", block_number)], ) .await; - match raw_receipts { - Ok(value) => { - let receipts: Result, Error> = - serde_json::from_value(value); - - match receipts { - Ok(receipts) => { - let mut db_receipts: Vec = - Vec::new(); - - let mut db_transaction_logs: Vec = - Vec::new(); - - let mut db_contracts: Vec = - Vec::new(); - - for receipt in receipts { - let db_contract = - receipt.contract_address.map(|_| { - DatabaseContract::from_rpc( - &receipt, - self.chain.id, - ) - }); - - match db_contract.is_some() { - true => { - db_contracts.push(db_contract.unwrap()) - } - false => (), - } + match receipts { + Ok(receipts) => { + let mut db_logs: Vec = Vec::new(); + let mut db_contracts: Vec = Vec::new(); - for log in receipt.logs.iter() { - let db_log = DatabaseLog::from_rpc( - log, - self.chain.id, - block_timestamp, - block_number, - ); + for receipt in receipts.iter() { + let status = receipt.status(); - db_transaction_logs.push(db_log) - } + if status && receipt.contract_address.is_some() { + db_contracts.push(DatabaseContract::from_rpc( + receipt, + self.chain_id, + )); + } - db_receipts.push(receipt); - } + for log in receipt.inner.logs() { + let db_log = DatabaseLog::from_rpc( + log, + self.chain_id, + block_timestamp, + block_number, + ); - Some(( - db_receipts, - db_transaction_logs, - db_contracts, - )) + db_logs.push(db_log) } - Err(_) => None, } + + Some((receipts, db_logs, db_contracts)) } Err(_) => None, } diff --git a/src/utils/dex_factories.rs b/src/utils/dex_factories.rs new file mode 100644 index 0000000..99d91b7 --- /dev/null +++ b/src/utils/dex_factories.rs @@ -0,0 +1,598 @@ +use alloy::primitives::Address; +use std::collections::HashMap; + +/// DEX protocol information +#[derive(Debug, Clone)] +pub struct DexInfo { + pub name: &'static str, + pub version: &'static str, +} + +impl DexInfo { + pub fn display_name(&self) -> String { + if self.version.is_empty() { + self.name.to_string() + } else { + format!("{} {}", self.name, self.version) + } + } +} + +/// DEX router addresses mapped by chain ID for automatic detection +#[derive(Clone)] +pub struct DexRouters { + // Map: chain_id -> router_address -> DexInfo + routers: HashMap>, +} + +impl DexRouters { + pub fn new() -> Self { + let mut routers = HashMap::new(); + + // ========== Ethereum (chain_id: 1) ========== + let mut eth_routers = HashMap::new(); + + // Uniswap + eth_routers.insert( + "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D".parse().unwrap(), + DexInfo { name: "Uniswap", version: "V2" }, + ); + eth_routers.insert( + "0xE592427A0AEce92De3Edee1F18E0157C05861564".parse().unwrap(), + DexInfo { name: "Uniswap", version: "V3" }, + ); + eth_routers.insert( + "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45".parse().unwrap(), + DexInfo { name: "Uniswap", version: "V3" }, + ); + + // SushiSwap + eth_routers.insert( + "0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F".parse().unwrap(), + DexInfo { name: "SushiSwap", version: "V2" }, + ); + + // Balancer + eth_routers.insert( + "0xBA12222222228d8Ba445958a75a0704d566BF2C8".parse().unwrap(), + DexInfo { name: "Balancer", version: "V2" }, + ); + + // 1inch + eth_routers.insert( + "0x1111111254EEB25477B68fb85Ed929f73A960582".parse().unwrap(), + DexInfo { name: "1inch", version: "V5" }, + ); + eth_routers.insert( + "0x1111111254fb6c44bAC0beD2854e76F90643097d".parse().unwrap(), + DexInfo { name: "1inch", version: "V4" }, + ); + + // Curve + eth_routers.insert( + "0x99a58482BD7f6B857d7E1f08Cd40A4c2a0b3053f".parse().unwrap(), + DexInfo { name: "Curve", version: "V1" }, + ); + eth_routers.insert( + "0x4c6e1eF2D04b53d1b16014ceEd20e13f1e00e27F".parse().unwrap(), + DexInfo { name: "Curve", version: "V2" }, + ); + + // DODO + eth_routers.insert( + "0x6B0431840294e53f1991bF8051413d90b8692CCb".parse().unwrap(), + DexInfo { name: "DODO", version: "V1" }, + ); + eth_routers.insert( + "0x3E712033605604bC3da248719D46B6b61a341142".parse().unwrap(), + DexInfo { name: "DODO", version: "V2" }, + ); + + // Curve 3Crv (deprecated but tracking) + eth_routers.insert( + "0x445FE580eF8d70FF569aB36e80c647af338db351".parse().unwrap(), + DexInfo { name: "Curve", version: "3Crv" }, + ); + + // Kyber + eth_routers.insert( + "0x1c87257F5e8609940Bc751a07BB085Bb7Fed0c64".parse().unwrap(), + DexInfo { name: "Kyber", version: "V3" }, + ); + + // WooFi on Ethereum + eth_routers.insert( + "0xC90bFE9951a4Efbf20aCa5ECd9966b2bF8A01294".parse().unwrap(), + DexInfo { name: "WooFi", version: "" }, + ); + + // Fraxswap + eth_routers.insert( + "0xC14d550632db8592D1243Edc8B95b0Ad06703867".parse().unwrap(), + DexInfo { name: "Fraxswap", version: "" }, + ); + + // Shibaswap + eth_routers.insert( + "0x03f7724180AA6b939894B5Ca4314783B0b36b329".parse().unwrap(), + DexInfo { name: "ShibaSwap", version: "" }, + ); + + routers.insert(1, eth_routers); + + // ========== BSC (chain_id: 56) ========== + let mut bsc_routers = HashMap::new(); + + // PancakeSwap + bsc_routers.insert( + "0x10ED43C718714eb63d5aA57B78B54704E256024E".parse().unwrap(), + DexInfo { name: "PancakeSwap", version: "V2" }, + ); + bsc_routers.insert( + "0x1b81D678ffb9C0263b24A97847620C99d213eB14".parse().unwrap(), + DexInfo { name: "PancakeSwap", version: "V3" }, + ); + bsc_routers.insert( + "0x13f4EA83D0bd40E75C8222255bc855a974568Dd4".parse().unwrap(), + DexInfo { name: "PancakeSwap", version: "V3" }, + ); + + // Uniswap on BSC + bsc_routers.insert( + "0xB971eF87ede563556b2ED4b1C0b0019111Dd85d2".parse().unwrap(), + DexInfo { name: "Uniswap", version: "V3" }, + ); + + // SushiSwap on BSC + bsc_routers.insert( + "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506".parse().unwrap(), + DexInfo { name: "SushiSwap", version: "V2" }, + ); + + // Biswap + bsc_routers.insert( + "0x3a6d8cA21D1CF76F653A67577FA0D27453350dD8".parse().unwrap(), + DexInfo { name: "Biswap", version: "V2" }, + ); + + // ApeSwap + bsc_routers.insert( + "0xcF0feBd3f17CEf5b47b0cD257aCf6025c5BFf3b7".parse().unwrap(), + DexInfo { name: "ApeSwap", version: "" }, + ); + + // BabySwap + bsc_routers.insert( + "0x325E343f1dE602396E256B67eFd1F61C3A6B38Bd".parse().unwrap(), + DexInfo { name: "BabySwap", version: "" }, + ); + + // Balancer on BSC + bsc_routers.insert( + "0xBA12222222228d8Ba445958a75a0704d566BF2C8".parse().unwrap(), + DexInfo { name: "Balancer", version: "V2" }, + ); + + // DODO on BSC + bsc_routers.insert( + "0x8F8Bb984e652Cb8D0aa7E399189dD6C7e2F90f5E".parse().unwrap(), + DexInfo { name: "DODO", version: "V2" }, + ); + + // Wault Finance + bsc_routers.insert( + "0xD48745E1F8dB63Ba37e7300F2C4Ee3629D2a58a6".parse().unwrap(), + DexInfo { name: "Wault", version: "" }, + ); + + // Bakery Swap + bsc_routers.insert( + "0xCDe540411ECFb16eC3DC027ed4Cc912FFbE31405".parse().unwrap(), + DexInfo { name: "BakerySwap", version: "" }, + ); + + // SafeMoon + bsc_routers.insert( + "0x05fF2B0DB69458A0750Bada338Cb0455B5148e8E".parse().unwrap(), + DexInfo { name: "SafeMoon", version: "" }, + ); + + // Ellipsis Finance (curve fork) + bsc_routers.insert( + "0x7552c756E293f6b5c754eF32881Ec9b43215de26".parse().unwrap(), + DexInfo { name: "Ellipsis", version: "" }, + ); + + // Thena (Solidly fork on BSC) + bsc_routers.insert( + "0xd4ae6eCA985340Dd434D38F470aCCce4DC78D109".parse().unwrap(), + DexInfo { name: "Thena", version: "V1" }, + ); + bsc_routers.insert( + "0x327Dd3208f0bCF590A66110aCB6e5e6941A4EfA0".parse().unwrap(), + DexInfo { name: "Thena", version: "Fusion" }, + ); + + // WooFi on BSC + bsc_routers.insert( + "0x4f4Fd4290c9bB49764701803AF6445c5b03E8f06".parse().unwrap(), + DexInfo { name: "WooFi", version: "" }, + ); + + // iZiSwap on BSC + bsc_routers.insert( + "0xBd3bd95529e0784aD973FD14928eEDF3678cfad8".parse().unwrap(), + DexInfo { name: "iZiSwap", version: "" }, + ); + + routers.insert(56, bsc_routers); + + // ========== Arbitrum (chain_id: 42161) ========== + let mut arbitrum_routers = HashMap::new(); + + // Uniswap on Arbitrum + arbitrum_routers.insert( + "0xE592427A0AEce92De3Edee1F18E0157C05861564".parse().unwrap(), + DexInfo { name: "Uniswap", version: "V3" }, + ); + arbitrum_routers.insert( + "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45".parse().unwrap(), + DexInfo { name: "Uniswap", version: "V3" }, + ); + + // SushiSwap on Arbitrum + arbitrum_routers.insert( + "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506".parse().unwrap(), + DexInfo { name: "SushiSwap", version: "V2" }, + ); + + // Camelot + arbitrum_routers.insert( + "0xc873fEcbd354f5A56E00E710B90EF4201db2448d".parse().unwrap(), + DexInfo { name: "Camelot", version: "V2" }, + ); + arbitrum_routers.insert( + "0x1F721E2E82F6676FCE4eA07A5958cF098D339e18".parse().unwrap(), + DexInfo { name: "Camelot", version: "V3" }, + ); + + // Balancer on Arbitrum + arbitrum_routers.insert( + "0xBA12222222228d8Ba445958a75a0704d566BF2C8".parse().unwrap(), + DexInfo { name: "Balancer", version: "V2" }, + ); + + // TraderJoe on Arbitrum + arbitrum_routers.insert( + "0xb4315e873dBcf96Ffd0acd8EA43f689D8c20fB30".parse().unwrap(), + DexInfo { name: "TraderJoe", version: "V2" }, + ); + + // DODO V2 on Arbitrum + arbitrum_routers.insert( + "0x88d7D573Ae20f34384D50fa5f1d2ff1E441667e2".parse().unwrap(), + DexInfo { name: "DODO", version: "V2" }, + ); + + // Aave on Arbitrum (lending protocol, not DEX swap) + arbitrum_routers.insert( + "0x794a61358D6845594F94dc1DB02A252b5b4814aD".parse().unwrap(), + DexInfo { name: "Aave", version: "V3" }, + ); + + // GMX + arbitrum_routers.insert( + "0xaBBc3E6db6a476353B5301aEA43f25AB0cFFb3B1".parse().unwrap(), + DexInfo { name: "GMX", version: "" }, + ); + + // 1inch on Arbitrum + arbitrum_routers.insert( + "0x1111111254fb6c44bAC0beD2854e76F90643097d".parse().unwrap(), + DexInfo { name: "1inch", version: "V5" }, + ); + + // Gains Network + arbitrum_routers.insert( + "0x18d96f45F95b73975033547eae59b02dCFF24635".parse().unwrap(), + DexInfo { name: "Gains Network", version: "" }, + ); + + // Ramses (Solidly fork on Arbitrum) + arbitrum_routers.insert( + "0xAAA87963EFeB6f7E0a2711F397663105Acb1805e".parse().unwrap(), + DexInfo { name: "Ramses", version: "V1" }, + ); + arbitrum_routers.insert( + "0xAA23611badAFB62D37E7295A682D21960ac85A90".parse().unwrap(), + DexInfo { name: "Ramses", version: "V2" }, + ); + + // WooFi on Arbitrum + arbitrum_routers.insert( + "0x9aEd3A8896A85FE9a8CAc52C9B402D092B629a30".parse().unwrap(), + DexInfo { name: "WooFi", version: "" }, + ); + + // Zyberswap (Algebra fork) + arbitrum_routers.insert( + "0x16e71B13fE6079B4312063F7E81F76d165Ad32Ad".parse().unwrap(), + DexInfo { name: "Zyberswap", version: "" }, + ); + + routers.insert(42161, arbitrum_routers); + + // ========== Optimism (chain_id: 10) ========== + let mut optimism_routers = HashMap::new(); + + // Uniswap on Optimism + optimism_routers.insert( + "0xE592427A0AEce92De3Edee1F18E0157C05861564".parse().unwrap(), + DexInfo { name: "Uniswap", version: "V3" }, + ); + optimism_routers.insert( + "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45".parse().unwrap(), + DexInfo { name: "Uniswap", version: "V3" }, + ); + + // Velodrome V1 + optimism_routers.insert( + "0x9c12939334C3742416f400C3793D6d271Fd3666f".parse().unwrap(), + DexInfo { name: "Velodrome", version: "V1" }, + ); + // Velodrome V2 + optimism_routers.insert( + "0xa062aE8A9c5e11aaA026fc2670B0D65cCc8B2858".parse().unwrap(), + DexInfo { name: "Velodrome", version: "V2" }, + ); + + // WooFi on Optimism + optimism_routers.insert( + "0x4c4AF8DBc524681930a27b2F1Af5bcC8062E6fB7".parse().unwrap(), + DexInfo { name: "WooFi", version: "" }, + ); + + // SushiSwap on Optimism + optimism_routers.insert( + "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506".parse().unwrap(), + DexInfo { name: "SushiSwap", version: "V2" }, + ); + + // Balancer on Optimism + optimism_routers.insert( + "0xBA12222222228d8Ba445958a75a0704d566BF2C8".parse().unwrap(), + DexInfo { name: "Balancer", version: "V2" }, + ); + + // Aave on Optimism (lending protocol, not DEX swap) + optimism_routers.insert( + "0x794a61358D6845594F94dc1DB02A252b5b4814aD".parse().unwrap(), + DexInfo { name: "Aave", version: "V3" }, + ); + + // 1inch on Optimism + optimism_routers.insert( + "0x1111111254fb6c44bAC0beD2854e76F90643097d".parse().unwrap(), + DexInfo { name: "1inch", version: "V5" }, + ); + + // Synthetix + optimism_routers.insert( + "0x2e5dB100552b932b299c3cc3b0253481fFEbA513".parse().unwrap(), + DexInfo { name: "Synthetix", version: "" }, + ); + + // Kwenta (perps) + optimism_routers.insert( + "0x8dAEBADE922dF735c38C80C7eBD708Af50815fAa".parse().unwrap(), + DexInfo { name: "Kwenta", version: "" }, + ); + + routers.insert(10, optimism_routers); + + // ========== Base (chain_id: 8453) ========== + let mut base_routers = HashMap::new(); + + // Uniswap on Base + base_routers.insert( + "0x2626664c2603336E57B271c5C0b26F421741e481".parse().unwrap(), + DexInfo { name: "Uniswap", version: "V3" }, + ); + base_routers.insert( + "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24".parse().unwrap(), + DexInfo { name: "Uniswap", version: "V3" }, + ); + + // Aerodrome V1 + base_routers.insert( + "0xcF77a3ba9A5CA399B7c97c74d54e5b1Beb874e43".parse().unwrap(), + DexInfo { name: "Aerodrome", version: "V1" }, + ); + // Aerodrome V2 + base_routers.insert( + "0x6Cb442acF35158D5eDa88fe602221b67B400Be3E".parse().unwrap(), + DexInfo { name: "Aerodrome", version: "V2" }, + ); + + // WooFi on Base + base_routers.insert( + "0x27425e9FB6A9A625E8484CFD9620b259571F6E57".parse().unwrap(), + DexInfo { name: "WooFi", version: "" }, + ); + + // Alien Base + base_routers.insert( + "0x8c1A3cF8f83074169FE5D7aD50B978e1cD6b37c7".parse().unwrap(), + DexInfo { name: "AlienBase", version: "" }, + ); + + // SushiSwap on Base + base_routers.insert( + "0x6BDED42c6DA8FBf0d2bA55B2fa120C5e0c8D7891".parse().unwrap(), + DexInfo { name: "SushiSwap", version: "V2" }, + ); + + // BaseSwap + base_routers.insert( + "0x327Df1E6de05895d2ab08513aaDD9313Fe505d86".parse().unwrap(), + DexInfo { name: "BaseSwap", version: "" }, + ); + + // DODO V2 on Base + base_routers.insert( + "0x6B0431840294e53f1991bF8051413d90b8692CCb".parse().unwrap(), + DexInfo { name: "DODO", version: "V2" }, + ); + + // Aave on Base (lending protocol, not DEX swap) + base_routers.insert( + "0x794a61358D6845594F94dc1DB02A252b5b4814aD".parse().unwrap(), + DexInfo { name: "Aave", version: "V3" }, + ); + + // Balancer on Base + base_routers.insert( + "0xBA12222222228d8Ba445958a75a0704d566BF2C8".parse().unwrap(), + DexInfo { name: "Balancer", version: "V2" }, + ); + + // 1inch on Base + base_routers.insert( + "0x1111111254fb6c44bAC0beD2854e76F90643097d".parse().unwrap(), + DexInfo { name: "1inch", version: "V5" }, + ); + + // Maverick + base_routers.insert( + "0x32aFc0b3f1dFd463B4bFDc4C92f9DF95ed66D08f".parse().unwrap(), + DexInfo { name: "Maverick", version: "V1" }, + ); + + routers.insert(8453, base_routers); + + // ========== Avalanche (chain_id: 43114) ========== + let mut avalanche_routers = HashMap::new(); + + // TraderJoe + avalanche_routers.insert( + "0x60aE616a2155Ee3d9A68541Ba4544862310933d4".parse().unwrap(), + DexInfo { name: "TraderJoe", version: "V1" }, + ); + avalanche_routers.insert( + "0xb4315e873dBcf96Ffd0acd8EA43f689D8c20fB30".parse().unwrap(), + DexInfo { name: "TraderJoe", version: "V2" }, + ); + + // Pangolin + avalanche_routers.insert( + "0xE54Ca86531e17Ef3616d22Ca28b0D458b6C89106".parse().unwrap(), + DexInfo { name: "Pangolin", version: "" }, + ); + + // SushiSwap on Avalanche + avalanche_routers.insert( + "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506".parse().unwrap(), + DexInfo { name: "SushiSwap", version: "V2" }, + ); + + // DODO V2 on Avalanche + avalanche_routers.insert( + "0xb27682b145913e06bdb3d379762cf87e80e3c6e3".parse().unwrap(), + DexInfo { name: "DODO", version: "V2" }, + ); + + // Aave on Avalanche (lending protocol, not DEX swap) + avalanche_routers.insert( + "0x794a61358D6845594F94dc1DB02A252b5b4814aD".parse().unwrap(), + DexInfo { name: "Aave", version: "V3" }, + ); + + // 1inch on Avalanche + avalanche_routers.insert( + "0x1111111254fb6c44bAC0beD2854e76F90643097d".parse().unwrap(), + DexInfo { name: "1inch", version: "V5" }, + ); + + // Balancer on Avalanche + avalanche_routers.insert( + "0xBA12222222228d8Ba445958a75a0704d566BF2C8".parse().unwrap(), + DexInfo { name: "Balancer", version: "V2" }, + ); + + // Platypus + avalanche_routers.insert( + "0x66357dCaCe80353121602d9C76Db1cA6a7b16D8d".parse().unwrap(), + DexInfo { name: "Platypus", version: "" }, + ); + + // Teddy + avalanche_routers.insert( + "0x54eAacE40807D8b3927F59985d2Ef8d2bECC5e76".parse().unwrap(), + DexInfo { name: "Teddy", version: "" }, + ); + + // WooFi on Avalanche + avalanche_routers.insert( + "0xC22FBb3133dF781E6C25ea6acebe2D2Bb8CeA2f9".parse().unwrap(), + DexInfo { name: "WooFi", version: "" }, + ); + + // Pharaoh (Solidly fork on Avalanche) + avalanche_routers.insert( + "0xAAAE99091Fbb28D400029052821653c1C752483B".parse().unwrap(), + DexInfo { name: "Pharaoh", version: "" }, + ); + + routers.insert(43114, avalanche_routers); + + Self { routers } + } + + /// Get DEX info from router address + pub fn get_dex_from_router( + &self, + chain_id: u64, + router: &Address, + ) -> Option<&DexInfo> { + self.routers + .get(&chain_id) + .and_then(|chain_routers| chain_routers.get(router)) + } + + /// Get the dominant V2-style DEX for a chain when router detection fails + /// This helps properly label Solidly forks (Velodrome, Aerodrome, Thena, etc.) + /// which emit the same Swap event signature as Uniswap V2 + pub fn get_default_v2_dex(&self, chain_id: u64) -> &'static str { + match chain_id { + 1 => "Uniswap V2", // Ethereum - Uniswap V2 dominant + 56 => "PancakeSwap V2", // BSC - PancakeSwap dominant + 42161 => "Camelot", // Arbitrum - Camelot/Ramses both popular, Camelot more common + 10 => "Velodrome", // Optimism - Velodrome dominant + 8453 => "Aerodrome", // Base - Aerodrome dominant + 43114 => "TraderJoe", // Avalanche - TraderJoe dominant + 137 => "QuickSwap", // Polygon - QuickSwap dominant + 250 => "SpookySwap", // Fantom - SpookySwap dominant + _ => "DEX V2", // Generic fallback + } + } + + /// Get the dominant V3-style DEX for a chain when router detection fails + pub fn get_default_v3_dex(&self, chain_id: u64) -> &'static str { + match chain_id { + 1 => "Uniswap V3", // Ethereum + 56 => "PancakeSwap V3", // BSC + 42161 => "Uniswap V3", // Arbitrum + 10 => "Uniswap V3", // Optimism + 8453 => "Uniswap V3", // Base + 43114 => "Uniswap V3", // Avalanche + 137 => "Uniswap V3", // Polygon + _ => "DEX V3", // Generic fallback + } + } +} + +impl Default for DexRouters { + fn default() -> Self { + Self::new() + } +} diff --git a/src/utils/events.rs b/src/utils/events.rs index ed2bc45..f856ac9 100644 --- a/src/utils/events.rs +++ b/src/utils/events.rs @@ -1,103 +1,51 @@ -use ethabi::ParamType; -use ethers::abi::ethabi; +pub const TRANSFER_EVENTS_SIGNATURE: &str = + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; -pub fn transfer_event() -> ethabi::Event { - ethabi::Event { - name: "Transfer".to_owned(), - inputs: vec![ - ethabi::EventParam { - name: "from".to_owned(), - kind: ParamType::Address, - indexed: true, - }, - ethabi::EventParam { - name: "to".to_owned(), - kind: ParamType::Address, - indexed: true, - }, - ethabi::EventParam { - name: "amount".to_owned(), - kind: ParamType::Uint(256), - indexed: false, - }, - ], - anonymous: false, - } -} +pub const ERC1155_TRANSFER_SINGLE_EVENT_SIGNATURE: &str = + "0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"; -pub static TRANSFER_EVENTS_SIGNATURE: &str = - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"; +pub const ERC1155_TRANSFER_BATCH_EVENT_SIGNATURE: &str = + "0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb"; -pub fn erc1155_transfer_single_event() -> ethabi::Event { - ethabi::Event { - name: "TransferSingle".to_owned(), - inputs: vec![ - ethabi::EventParam { - name: "operator".to_owned(), - kind: ParamType::Address, - indexed: true, - }, - ethabi::EventParam { - name: "from".to_owned(), - kind: ParamType::Address, - indexed: true, - }, - ethabi::EventParam { - name: "to".to_owned(), - kind: ParamType::Address, - indexed: true, - }, - ethabi::EventParam { - name: "id".to_owned(), - kind: ParamType::Uint(256), - indexed: false, - }, - ethabi::EventParam { - name: "value".to_owned(), - kind: ParamType::Uint(256), - indexed: false, - }, - ], - anonymous: false, - } -} +// Uniswap V2 Swap: Swap(address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to) +// Also used by: PancakeSwap V2, SushiSwap V2 (Uniswap V2 forks) +pub const UNISWAP_V2_SWAP_EVENT_SIGNATURE: &str = + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822"; -pub static ERC1155_TRANSFER_SINGLE_EVENT_SIGNATURE: &str = - "0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"; +// Uniswap V3 Swap: Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick) +// Also used by: PancakeSwap V3 (Uniswap V3 fork) +pub const UNISWAP_V3_SWAP_EVENT_SIGNATURE: &str = + "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67"; -pub fn erc1155_transfer_batch_event() -> ethabi::Event { - ethabi::Event { - name: "TransferBatch".to_owned(), - inputs: vec![ - ethabi::EventParam { - name: "operator".to_owned(), - kind: ParamType::Address, - indexed: true, - }, - ethabi::EventParam { - name: "from".to_owned(), - kind: ParamType::Address, - indexed: true, - }, - ethabi::EventParam { - name: "to".to_owned(), - kind: ParamType::Address, - indexed: true, - }, - ethabi::EventParam { - name: "ids".to_owned(), - kind: ParamType::Array(Box::new(ParamType::Uint(256))), - indexed: false, - }, - ethabi::EventParam { - name: "values".to_owned(), - kind: ParamType::Array(Box::new(ParamType::Uint(256))), - indexed: false, - }, - ], - anonymous: false, - } -} +// Curve TokenExchange: TokenExchange(address indexed buyer, uint256 sold_id, uint256 tokens_sold, uint256 bought_id, uint256 tokens_bought) +pub const CURVE_TOKEN_EXCHANGE_EVENT_SIGNATURE: &str = + "0x8b3e96f2b38596c00065310677151151122ba8153782eeec1e3567cc2a8f3b8b"; -pub static ERC1155_TRANSFER_BATCH_EVENT_SIGNATURE: &str = - "0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb"; +// Curve TokenExchangeUnderlying: TokenExchangeUnderlying(address indexed buyer, int128 sold_id, uint256 tokens_sold, int128 bought_id, uint256 tokens_bought) +// Used for meta pools to swap underlying tokens directly +pub const CURVE_TOKEN_EXCHANGE_UNDERLYING_EVENT_SIGNATURE: &str = + "0xd013ca23e77a65003c2c659c5442c00c805371b7fc1ebd4c206c41d1536bd90b"; + +// Balancer V2 Swap: Swap(bytes32 indexed poolId, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut) +pub const BALANCER_SWAP_EVENT_SIGNATURE: &str = + "0x908fb5ee0f4747fbf483d1ff1405d916f86720130038586180403d7e46b6b5f8"; + +// DODO Swap: Swap(address indexed sender, address indexed receiver, address tokenB, address tokenQuote, uint256 payQuote, uint256 receiveBase) +pub const DODO_SWAP_EVENT_SIGNATURE: &str = + "0xc2c0b5e1ab1ec6b34b26ff79c0e1be2fdc89c4ed0cf2cc9e906f986de7ded41f"; + +// Kyber Swapped: Swapped(bytes32 indexed pool, address indexed router, address indexed token0, address indexed token1, int256 delta0, int256 delta1) +pub const KYBER_SWAPPED_EVENT_SIGNATURE: &str = + "0xdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496"; + +// Maverick SwapFilled: SwapFilled(address indexed recipient, uint256 amountAIn, uint256 amountBIn, uint256 amountAOut, uint256 amountBOut) +pub const MAVERICK_SWAP_FILLED_EVENT_SIGNATURE: &str = + "0xdb5f3876bb8b6c00fb1a4c32c5947c5ad45a70c07d30a1a3fd90f3ad8dd86c3f"; + +// TraderJoe V2.1 LB Swap: Swap(address indexed sender, address indexed to, uint24 id, bytes32 amountsIn, bytes32 amountsOut) +pub const TRADERJOE_LB_SWAP_EVENT_SIGNATURE: &str = + "0xad7d6f97abf51ce18e17a38f4d70e975be9c0708474987bb3e26ad21bd93ca70"; + +// WooFi WooSwap: WooSwap(address indexed from, address indexed to, address fromToken, address toToken, uint256 fromAmount, uint256 toAmount, address rebateTo) +pub const WOOFI_SWAP_EVENT_SIGNATURE: &str = + "0x74ef34e2ea7c5d9f7b7ed44e97ad44b4303416c3a660c3fb5b3bdb95a1d6abd3"; diff --git a/src/utils/format.rs b/src/utils/format.rs index ec5d14a..0d99f93 100644 --- a/src/utils/format.rs +++ b/src/utils/format.rs @@ -1,52 +1,7 @@ -use ethers::types::{Bytes, H160, H256, H64}; -use primitive_types::U256; +use alloy::primitives::U256; use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; use serde_with::{DeserializeAs, SerializeAs}; -pub fn format_nonce(h: H64) -> String { - format!("{:?}", h) -} - -pub fn format_hash(h: H256) -> String { - format!("{:?}", h) -} - -pub fn format_address(h: H160) -> String { - format!("{:?}", h) -} - -pub fn format_bytes(b: &Bytes) -> String { - serde_json::to_string(b).unwrap().replace('\"', "") -} - -pub fn decode_bytes(s: String) -> Vec { - let without_prefix = &s[2..]; - hex::decode(without_prefix).unwrap() -} - -pub fn format_bytes_slice(b: &[u8]) -> String { - format!("0x{}", hex::encode(b)) -} - -pub fn byte4_from_input(input: &str) -> [u8; 4] { - let input_sanitized = input.strip_prefix("0x").unwrap(); - - if input_sanitized.is_empty() { - return [0x00, 0x00, 0x00, 0x00]; - } - - let input_bytes = hex::decode(input_sanitized).unwrap(); - - if input_bytes.len() < 4 { - return [0x00, 0x00, 0x00, 0x00]; - } - - let byte4: [u8; 4] = - [input_bytes[0], input_bytes[1], input_bytes[2], input_bytes[3]]; - - byte4 -} - pub struct SerU256(()); impl SerializeAs for SerU256 { @@ -54,9 +9,9 @@ impl SerializeAs for SerU256 { where S: Serializer, { - let mut buf: [u8; 32] = [0; 32]; - x.to_little_endian(&mut buf); - buf.serialize(serializer) + // Serialize as hex string for ClickHouse compatibility + let hex_string = format!("{:x}", x); + hex_string.serialize(serializer) } } @@ -65,7 +20,7 @@ impl<'de> DeserializeAs<'de, U256> for SerU256 { where D: Deserializer<'de>, { - let u: [u8; 32] = Deserialize::deserialize(deserializer)?; - Ok(U256::from_little_endian(&u)) + let s: String = Deserialize::deserialize(deserializer)?; + U256::from_str_radix(&s, 16).map_err(serde::de::Error::custom) } } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 1168aef..af6cfe0 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,2 +1,3 @@ +pub mod dex_factories; pub mod events; pub mod format;