diff --git a/Cargo.lock b/Cargo.lock index fdbbf68dd..e6df948dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1554,15 +1554,6 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - [[package]] name = "asn1-rs" version = "0.5.2" @@ -1845,17 +1836,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "async_io_stream" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" -dependencies = [ - "futures", - "pharos", - "rustc_version 0.4.1", -] - [[package]] name = "asynchronous-codec" version = "0.6.2" @@ -2093,12 +2073,6 @@ version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - [[package]] name = "beef" version = "0.5.2" @@ -2146,6 +2120,25 @@ dependencies = [ "serde", ] +[[package]] +name = "bip32" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db40d3dfbeab4e031d78c844642fa0caa0b0db11ce1607ac9d2986dff1405c69" +dependencies = [ + "bs58 0.5.1", + "hmac 0.12.1", + "k256", + "once_cell", + "pbkdf2 0.12.2", + "rand_core 0.6.4", + "ripemd", + "secp256k1 0.27.0", + "sha2 0.10.9", + "subtle", + "zeroize", +] + [[package]] name = "bip39" version = "2.2.0" @@ -2157,30 +2150,15 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec 0.6.3", -] - [[package]] name = "bit-set" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec 0.8.0", + "bit-vec", ] -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - [[package]] name = "bit-vec" version = "0.8.0" @@ -2647,15 +2625,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "camino" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" -dependencies = [ - "serde_core", -] - [[package]] name = "caps" version = "0.5.5" @@ -2666,29 +2635,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[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 1.0.26", - "serde", - "serde_json", - "thiserror 1.0.69", -] - [[package]] name = "cast" version = "0.3.0" @@ -2869,58 +2815,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" -[[package]] -name = "coins-bip32" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" -dependencies = [ - "bs58 0.5.1", - "coins-core", - "digest 0.10.7", - "hmac 0.12.1", - "k256", - "serde", - "sha2 0.10.9", - "thiserror 1.0.69", -] - -[[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 0.12.1", - "once_cell", - "pbkdf2 0.12.2", - "rand 0.8.5", - "sha2 0.10.9", - "thiserror 1.0.69", -] - -[[package]] -name = "coins-core" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" -dependencies = [ - "base64 0.21.7", - "bech32", - "bs58 0.5.1", - "digest 0.10.7", - "generic-array", - "hex", - "ripemd", - "serde", - "serde_derive", - "sha2 0.10.9", - "sha3", - "thiserror 1.0.69", -] - [[package]] name = "colorchoice" version = "1.0.3" @@ -3774,7 +3668,7 @@ dependencies = [ "arrayvec 0.7.6", "ctr", "delay_map", - "enr 0.12.1", + "enr", "fnv", "futures", "hashlink", @@ -4034,15 +3928,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ena" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" -dependencies = [ - "log", -] - [[package]] name = "encode_unicode" version = "1.0.0" @@ -4058,24 +3943,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[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 0.8.5", - "rlp", - "serde", - "sha3", - "zeroize", -] - [[package]] name = "enr" version = "0.12.1" @@ -4246,76 +4113,6 @@ dependencies = [ "windows-sys 0.48.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 0.10.7", - "hex", - "hmac 0.12.1", - "pbkdf2 0.11.0", - "rand 0.8.5", - "scrypt 0.10.0", - "serde", - "serde_json", - "sha2 0.10.9", - "sha3", - "thiserror 1.0.69", - "uuid 0.8.2", -] - -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror 1.0.69", - "uint 0.9.5", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash 0.8.0", - "impl-codec 0.6.0", - "impl-rlp", - "impl-serde 0.4.0", - "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 0.8.0", - "impl-codec 0.6.0", - "impl-rlp", - "impl-serde 0.4.0", - "primitive-types 0.12.2", - "scale-info", - "uint 0.9.5", -] - [[package]] name = "ethereum_hashing" version = "0.7.0" @@ -4367,254 +4164,6 @@ dependencies = [ "syn 2.0.101", ] -[[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 1.0.69", -] - -[[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 0.2.34", - "proc-macro2", - "quote", - "regex", - "reqwest 0.11.27", - "serde", - "serde_json", - "syn 2.0.101", - "toml 0.8.22", - "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.101", -] - -[[package]] -name = "ethers-core" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" -dependencies = [ - "arrayvec 0.7.6", - "bytes", - "cargo_metadata", - "chrono", - "const-hex", - "elliptic-curve", - "ethabi", - "generic-array", - "k256", - "num_enum", - "once_cell", - "open-fastrlp", - "rand 0.8.5", - "rlp", - "serde", - "serde_json", - "strum 0.26.3", - "syn 2.0.101", - "tempfile", - "thiserror 1.0.69", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "ethers-etherscan" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79e5973c26d4baf0ce55520bd732314328cabe53193286671b47144145b9649" -dependencies = [ - "chrono", - "ethers-core", - "reqwest 0.11.27", - "semver 1.0.26", - "serde", - "serde_json", - "thiserror 1.0.69", - "tracing", -] - -[[package]] -name = "ethers-middleware" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f9fdf09aec667c099909d91908d5eaf9be1bd0e2500ba4172c1d28bfaa43de" -dependencies = [ - "async-trait", - "auto_impl", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-providers", - "ethers-signers", - "futures-channel", - "futures-locks", - "futures-util", - "instant", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", - "tracing", - "tracing-futures", - "url 2.5.4", -] - -[[package]] -name = "ethers-providers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" -dependencies = [ - "async-trait", - "auto_impl", - "base64 0.21.7", - "bytes", - "const-hex", - "enr 0.10.0", - "ethers-core", - "futures-core", - "futures-timer", - "futures-util", - "hashers", - "http 0.2.12", - "instant", - "jsonwebtoken", - "once_cell", - "pin-project", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", - "tokio-tungstenite", - "tracing", - "tracing-futures", - "url 2.5.4", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "ws_stream_wasm", -] - -[[package]] -name = "ethers-signers" -version = "2.0.14" -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 0.8.5", - "sha2 0.10.9", - "thiserror 1.0.69", - "tracing", -] - -[[package]] -name = "ethers-solc" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66244a771d9163282646dbeffe0e6eca4dda4146b6498644e678ac6089b11edd" -dependencies = [ - "cfg-if 1.0.0", - "const-hex", - "dirs", - "dunce", - "ethers-core", - "glob", - "home", - "md-5", - "num_cpus", - "once_cell", - "path-slash", - "rayon", - "regex", - "semver 1.0.26", - "serde", - "serde_json", - "solang-parser", - "svm-rs", - "thiserror 1.0.69", - "tiny-keccak", - "tokio", - "tracing", - "walkdir", - "yansi 0.5.1", -] - [[package]] name = "event-listener" version = "2.5.3" @@ -4807,14 +4356,8 @@ dependencies = [ "byteorder", "rand 0.8.5", "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + "static_assertions", +] [[package]] name = "flate2" @@ -5007,16 +4550,6 @@ dependencies = [ "pin-project-lite", ] -[[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" @@ -5058,7 +4591,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ "gloo-timers 0.2.6", - "send_wrapper 0.4.0", + "send_wrapper", ] [[package]] @@ -5085,15 +4618,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -5289,26 +4813,6 @@ dependencies = [ "yup-oauth2", ] -[[package]] -name = "google-datastore1" -version = "5.0.4+20240226" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d822056b35f25b564e77b0cfd9bdcbad8fc5c891bf079d61536572d67bfc8e3" -dependencies = [ - "anyhow", - "google-apis-common", - "http 0.2.12", - "hyper 0.14.32", - "hyper-rustls 0.24.2", - "itertools 0.10.5", - "mime", - "serde", - "serde_json", - "tokio", - "tower-service", - "url 1.7.2", -] - [[package]] name = "google-secretmanager1" version = "5.0.5+20240621" @@ -5479,15 +4983,6 @@ dependencies = [ "serde", ] -[[package]] -name = "hashers" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" -dependencies = [ - "fxhash", -] - [[package]] name = "hashlink" version = "0.8.4" @@ -6427,24 +5922,6 @@ dependencies = [ "uint 0.10.0", ] -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" -dependencies = [ - "serde", -] - [[package]] name = "impl-serde" version = "0.5.0" @@ -6551,6 +6028,8 @@ dependencies = [ "anyhow", "async-process 1.8.1", "backon", + "bip32", + "bip39", "bollard", "borsh 1.5.7", "bs58 0.5.1", @@ -6561,8 +6040,6 @@ dependencies = [ "deadpool-redis", "ecdsa", "elliptic-curve", - "ethers", - "ethers-core", "futures", "generic-array", "hex", @@ -6601,7 +6078,7 @@ dependencies = [ "tracing", "tracing-subscriber 0.3.20", "url 2.5.4", - "uuid 1.18.1", + "uuid", ] [[package]] @@ -7060,20 +6537,6 @@ dependencies = [ "url 2.5.4", ] -[[package]] -name = "jsonwebtoken" -version = "8.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" -dependencies = [ - "base64 0.21.7", - "pem", - "ring 0.16.20", - "serde", - "serde_json", - "simple_asn1", -] - [[package]] name = "k256" version = "0.13.4" @@ -7118,36 +6581,6 @@ dependencies = [ "tiny-keccak", ] -[[package]] -name = "lalrpop" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" -dependencies = [ - "ascii-canvas", - "bit-set 0.5.3", - "ena", - "itertools 0.11.0", - "lalrpop-util", - "petgraph", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", - "walkdir", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" -dependencies = [ - "regex-automata", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -7753,16 +7186,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if 1.0.0", - "digest 0.10.7", -] - [[package]] name = "memchr" version = "2.7.4" @@ -7957,9 +7380,7 @@ dependencies = [ "clap", "deadpool-redis", "ed25519-zebra", - "ethabi", "futures-util", - "google-datastore1", "google-secretmanager1", "helios", "hex", @@ -9139,12 +8560,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - [[package]] name = "nix" version = "0.26.4" @@ -9562,31 +8977,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec 0.7.6", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "openssl" version = "0.10.72" @@ -9918,12 +9308,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[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" @@ -9955,7 +9339,7 @@ checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467" dependencies = [ "inlinable_string", "pear_codegen", - "yansi 1.0.1", + "yansi", ] [[package]] @@ -10020,26 +9404,6 @@ dependencies = [ "ucd-trie", ] -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.9.0", -] - -[[package]] -name = "pharos" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" -dependencies = [ - "futures", - "rustc_version 0.4.1", -] - [[package]] name = "phf" version = "0.11.3" @@ -10282,12 +9646,6 @@ dependencies = [ "zerocopy 0.8.25", ] -[[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.1.25" @@ -10335,9 +9693,6 @@ checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash 0.8.0", "impl-codec 0.6.0", - "impl-rlp", - "impl-serde 0.4.0", - "scale-info", "uint 0.9.5", ] @@ -10350,7 +9705,7 @@ dependencies = [ "fixed-hash 0.8.0", "impl-codec 0.7.1", "impl-num-traits", - "impl-serde 0.5.0", + "impl-serde", "scale-info", "uint 0.10.0", ] @@ -10448,7 +9803,7 @@ dependencies = [ "quote", "syn 2.0.101", "version_check", - "yansi 1.0.1", + "yansi", ] [[package]] @@ -10509,8 +9864,8 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ - "bit-set 0.8.0", - "bit-vec 0.8.0", + "bit-set", + "bit-vec", "bitflags 2.10.0", "lazy_static", "num-traits", @@ -11401,21 +10756,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ "bytes", - "rlp-derive", "rustc-hex", ] -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "rmp" version = "0.8.14" @@ -12035,18 +11378,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 0.12.1", - "pbkdf2 0.11.0", - "salsa20", - "sha2 0.10.9", -] - [[package]] name = "scrypt" version = "0.11.0" @@ -12236,9 +11567,6 @@ name = "semver" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" -dependencies = [ - "serde", -] [[package]] name = "semver-parser" @@ -12255,12 +11583,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" - [[package]] name = "serde" version = "1.0.228" @@ -12577,18 +11899,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "620a1d43d70e142b1d46a929af51d44f383db9c7a2ec122de2cd992ccfcf3c18" -[[package]] -name = "simple_asn1" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" -dependencies = [ - "num-bigint 0.4.6", - "num-traits", - "thiserror 2.0.12", - "time", -] - [[package]] name = "siphasher" version = "0.3.11" @@ -15027,20 +14337,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "solang-parser" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" -dependencies = [ - "itertools 0.11.0", - "lalrpop", - "lalrpop-util", - "phf", - "thiserror 1.0.69", - "unicode-xid", -] - [[package]] name = "sp-application-crypto" version = "43.0.0" @@ -15086,7 +14382,7 @@ dependencies = [ "futures", "hash-db", "hash256-std-hasher", - "impl-serde 0.5.0", + "impl-serde", "itertools 0.11.0", "k256", "libsecp256k1 0.7.2", @@ -15298,7 +14594,7 @@ version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee3b70ca340e41cde9d2e069d354508a6e37a6573d66f7cc38f11549002f64ec" dependencies = [ - "impl-serde 0.5.0", + "impl-serde", "parity-scale-codec", "ref-cast", "serde", @@ -15803,18 +15099,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "string_cache" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" -dependencies = [ - "new_debug_unreachable", - "parking_lot 0.12.3", - "phf_shared", - "precomputed-hash", -] - [[package]] name = "strsim" version = "0.10.0" @@ -16017,7 +15301,7 @@ dependencies = [ "frame-metadata", "hashbrown 0.14.5", "hex", - "impl-serde 0.5.0", + "impl-serde", "keccak-hash", "parity-scale-codec", "primitive-types 0.13.1", @@ -16093,7 +15377,7 @@ dependencies = [ "frame-metadata", "futures", "hex", - "impl-serde 0.5.0", + "impl-serde", "jsonrpsee 0.24.10", "parity-scale-codec", "primitive-types 0.13.1", @@ -16123,7 +15407,7 @@ dependencies = [ "pbkdf2 0.12.2", "regex", "schnorrkel", - "scrypt 0.11.0", + "scrypt", "secp256k1 0.30.0", "secrecy 0.10.3", "serde", @@ -16160,26 +15444,6 @@ dependencies = [ "syn 1.0.109", ] -[[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 0.11.27", - "semver 1.0.26", - "serde", - "serde_json", - "sha2 0.10.9", - "thiserror 1.0.69", - "url 2.5.4", - "zip", -] - [[package]] name = "syn" version = "1.0.109" @@ -16347,17 +15611,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - [[package]] name = "termcolor" version = "1.4.1" @@ -16839,16 +16092,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -17293,16 +16536,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom 0.2.16", - "serde", -] - [[package]] name = "uuid" version = "1.18.1" @@ -18163,25 +17396,6 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" -[[package]] -name = "ws_stream_wasm" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c173014acad22e83f16403ee360115b38846fe754e735c5d9d3803fe70c6abc" -dependencies = [ - "async_io_stream", - "futures", - "js-sys", - "log", - "pharos", - "rustc_version 0.4.1", - "send_wrapper 0.6.0", - "thiserror 2.0.12", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "wyz" version = "0.5.1" @@ -18241,12 +17455,6 @@ dependencies = [ "rustix 1.0.5", ] -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - [[package]] name = "yansi" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index 2d3380b2c..a110c3511 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ tracing-subscriber = { version = "0.3.20", default-features = false, features = "fmt", ] } url = { version = "2.4.0", features = ["serde"] } -ethabi = "18.0.0" + anchor-client = { version = "0.31.0", features = ["async"] } anchor-lang = "0.31.0" solana-sdk = "2.2.2" diff --git a/chain-signatures/node/Cargo.toml b/chain-signatures/node/Cargo.toml index 492378475..05c872c45 100644 --- a/chain-signatures/node/Cargo.toml +++ b/chain-signatures/node/Cargo.toml @@ -12,7 +12,7 @@ async-trait = "0.1" axum = "0.7.9" axum-extra = "0.9.6" chrono = "0.4.24" -google-datastore1 = "=5.0.4" + google-secretmanager1 = "5" hkdf = "0.12.4" highway = "1.1.0" @@ -71,7 +71,7 @@ tokio.workspace = true tracing.workspace = true tracing-subscriber.workspace = true url.workspace = true -ethabi.workspace = true + anchor-client.workspace = true anchor-lang.workspace = true solana-sdk.workspace = true diff --git a/chain-signatures/node/src/gcp/mod.rs b/chain-signatures/node/src/gcp/mod.rs index 0fa62b972..1553a7dfa 100644 --- a/chain-signatures/node/src/gcp/mod.rs +++ b/chain-signatures/node/src/gcp/mod.rs @@ -2,10 +2,9 @@ pub mod error; use crate::storage; -use google_datastore1::api::Key; -use google_datastore1::oauth2::AccessTokenAuthenticator; use google_secretmanager1::api::{AddSecretVersionRequest, SecretPayload}; use google_secretmanager1::oauth2::authenticator::ApplicationDefaultCredentialsTypes; +use google_secretmanager1::oauth2::AccessTokenAuthenticator; use google_secretmanager1::oauth2::{ ApplicationDefaultCredentialsAuthenticator, ApplicationDefaultCredentialsFlowOpts, }; @@ -71,14 +70,6 @@ impl SecretManagerService { } } -pub trait Keyable: KeyKind { - fn key(&self) -> Key; -} - -pub trait KeyKind { - fn kind() -> String; -} - #[derive(Clone)] pub struct GcpService { pub project_id: String, diff --git a/chain-signatures/node/src/indexer_common.rs b/chain-signatures/node/src/indexer_common.rs index 76209c78c..01468df1a 100644 --- a/chain-signatures/node/src/indexer_common.rs +++ b/chain-signatures/node/src/indexer_common.rs @@ -16,6 +16,8 @@ use crate::rpc::ContractStateWatcher; use crate::sign_bidirectional::BidirectionalTx; use crate::sign_bidirectional::BidirectionalTxId; use crate::sign_bidirectional::PendingRequestStatus; + +use alloy::primitives::keccak256; use anchor_lang::prelude::Pubkey; use k256::Scalar; use mpc_primitives::SignId; @@ -451,3 +453,70 @@ pub(crate) fn sender_string(sender: [u8; 32], source_chain: Chain) -> anyhow::Re _ => anyhow::bail!("Unsupported chain: {source_chain}"), } } + +/// Encode exactly as the legacy ethabi version: +/// (string, bytes, string, uint256, string, string, string, string) +/// +/// Alloy adds extra metadata that throws off the previous ethabi encoding +/// so this implementation manually encodes the data to match the previous +/// ethabi without importing it. +#[allow(clippy::too_many_arguments)] +pub fn ethabi_request_id( + sender: String, + payload: [u8; 32], + path: String, + key_version: u32, + chain_id: String, + algo: String, + dest: String, + params: String, +) -> [u8; 32] { + const HEAD_WORDS: usize = 8; + const WORD_SIZE: usize = 32; + + let head_size = HEAD_WORDS * WORD_SIZE; + let mut heads: Vec<[u8; WORD_SIZE]> = Vec::with_capacity(HEAD_WORDS); + let mut tails: Vec = Vec::new(); + + fn u256_word(value: u64) -> [u8; WORD_SIZE] { + let mut word = [0u8; WORD_SIZE]; + word[WORD_SIZE - 8..].copy_from_slice(&value.to_be_bytes()); + word + } + + fn push_dynamic( + heads: &mut Vec<[u8; WORD_SIZE]>, + tails: &mut Vec, + head_size: usize, + bytes: &[u8], + ) { + let offset = head_size + tails.len(); + heads.push(u256_word(offset as u64)); + tails.extend_from_slice(&u256_word(bytes.len() as u64)); + tails.extend_from_slice(bytes); + let padding = (WORD_SIZE - (bytes.len() % WORD_SIZE)) % WORD_SIZE; + tails.extend(std::iter::repeat_n(0u8, padding)); + } + + push_dynamic( + &mut heads, + &mut tails, + head_size, + sender.to_string().as_bytes(), + ); + push_dynamic(&mut heads, &mut tails, head_size, payload.as_slice()); + push_dynamic(&mut heads, &mut tails, head_size, path.as_bytes()); + heads.push(u256_word(key_version as u64)); + push_dynamic(&mut heads, &mut tails, head_size, chain_id.as_bytes()); + push_dynamic(&mut heads, &mut tails, head_size, algo.as_bytes()); + push_dynamic(&mut heads, &mut tails, head_size, dest.as_bytes()); + push_dynamic(&mut heads, &mut tails, head_size, params.as_bytes()); + + let mut encoded = Vec::with_capacity(head_size + tails.len()); + for head in heads { + encoded.extend_from_slice(&head); + } + encoded.extend_from_slice(&tails); + + *keccak256(encoded) +} diff --git a/chain-signatures/node/src/indexer_eth/abi.rs b/chain-signatures/node/src/indexer_eth/abi.rs new file mode 100644 index 000000000..407bf27b8 --- /dev/null +++ b/chain-signatures/node/src/indexer_eth/abi.rs @@ -0,0 +1,61 @@ +alloy::sol! { + #[sol(rpc)] + contract ChainSignatures { + struct SignRequest { + bytes32 payload; + string path; + uint32 keyVersion; + string algo; + string dest; + string params; + } + + struct AffinePoint { + uint256 x; + uint256 y; + } + + struct Signature { + AffinePoint bigR; + uint256 s; + uint8 recoveryId; + } + + function sign(SignRequest memory _request) external payable; + function getSignatureDeposit() external view returns (uint256); + + event SignatureRequested( + address sender, + bytes32 payload, + uint32 keyVersion, + uint256 deposit, + uint256 chainId, + string path, + string algo, + string dest, + string params + ); + + event SignatureResponded( + bytes32 indexed requestId, + address responder, + Signature signature + ); + } + + event SignatureRequestedEncoding( + address sender, + bytes payload, + string path, + uint32 keyVersion, + uint256 chainId, + string algo, + string dest, + string params + ); + + struct ChainSignaturesConstructor { + address mpcNetwork; + uint256 signatureDeposit; + } +} diff --git a/chain-signatures/node/src/indexer_eth/mod.rs b/chain-signatures/node/src/indexer_eth/mod.rs index b81b97d57..2a639c4fe 100644 --- a/chain-signatures/node/src/indexer_eth/mod.rs +++ b/chain-signatures/node/src/indexer_eth/mod.rs @@ -1,7 +1,9 @@ +pub mod abi; pub mod indexer_eth_direct_rpc; pub mod indexer_eth_helios; use crate::backlog::Backlog; +use crate::indexer_eth::abi::{ChainSignatures, SignatureRequestedEncoding}; use crate::mesh::MeshState; use crate::node_client::NodeClient; use crate::protocol::{Chain, IndexedSignRequest, Sign, SignRequestType}; @@ -9,11 +11,12 @@ use crate::respond_bidirectional::CompletedTx; use crate::rpc::ContractStateWatcher; use crate::sign_bidirectional::PendingRequestStatus; use crate::storage::app_data_storage::AppDataStorage; + use alloy::eips::BlockNumberOrTag; use alloy::primitives::hex::{self, ToHexExt}; use alloy::primitives::{Address, Bytes, U256}; use alloy::rpc::types::Log; -use alloy::sol_types::{sol, SolEvent}; +use alloy::sol_types::SolEvent; use k256::Scalar; use mpc_crypto::{kdf::derive_epsilon_eth, ScalarExt as _}; use mpc_primitives::{SignArgs, SignId, LATEST_MPC_KEY_VERSION}; @@ -303,43 +306,6 @@ pub struct EthSignRequest { pub key_version: u32, } -sol! { - event SignatureRequested( - address sender, - bytes32 payload, - uint32 keyVersion, - uint256 deposit, - uint256 chainId, - string path, - string algo, - string dest, - string params - ); - - event SignatureRequestedEncoding( - address sender, - bytes payload, - string path, - uint32 keyVersion, - uint256 chainId, - string algo, - string dest, - string params - ); - - struct Signature { - uint8 v; - bytes32 r; - bytes32 s; - } - - event SignatureResponded( - bytes32 indexed requestId, - address responder, - Signature signature - ); -} - fn sign_request_from_filtered_log(log: Log, total_timeout: Duration) -> Option { let event = parse_event(&log); tracing::debug!("found eth event: {:?}", event); @@ -522,7 +488,7 @@ async fn process_respond_events(logs: &[Log], backlog: &Backlog, sign_tx: mpsc:: fn sign_id_from_signature_responded_log(log: &Log) -> Option { if log .topic0() - .is_none_or(|topic| *topic != SignatureResponded::SIGNATURE_HASH) + .is_none_or(|topic| *topic != ChainSignatures::SignatureResponded::SIGNATURE_HASH) { return None; } @@ -977,8 +943,9 @@ impl EthereumIndexer { let (respond_logs, potential_request_logs): (Vec, Vec) = relevant_logs.into_iter().partition(|log| { - log.topic0() - .is_some_and(|topic| *topic == SignatureResponded::SIGNATURE_HASH) + log.topic0().is_some_and(|topic| { + *topic == ChainSignatures::SignatureResponded::SIGNATURE_HASH + }) }); if !respond_logs.is_empty() { @@ -988,8 +955,9 @@ impl EthereumIndexer { let request_logs: Vec = potential_request_logs .into_iter() .filter(|log| { - log.topic0() - .is_some_and(|topic| *topic == SignatureRequested::SIGNATURE_HASH) + log.topic0().is_some_and(|topic| { + *topic == ChainSignatures::SignatureRequested::SIGNATURE_HASH + }) }) .collect(); diff --git a/chain-signatures/node/src/indexer_hydration.rs b/chain-signatures/node/src/indexer_hydration.rs index 90a7c2332..d9cf06c06 100644 --- a/chain-signatures/node/src/indexer_hydration.rs +++ b/chain-signatures/node/src/indexer_hydration.rs @@ -1,21 +1,20 @@ use crate::backlog::Backlog; -use crate::indexer_common::SignatureEvent; +use crate::indexer_common::{ethabi_request_id, SignatureEvent}; use crate::indexer_sol::MAX_SECP256K1_SCALAR; use crate::mesh::MeshState; use crate::node_client::NodeClient; use crate::protocol::{Chain, IndexedSignRequest, Sign, SignRequestType}; use crate::rpc::ContractStateWatcher; use crate::sign_bidirectional::hash_rlp_data; + use alloy_sol_types::SolValue; use anyhow::{anyhow, Result}; -use ethabi::{encode, Token}; use k256::elliptic_curve::sec1::FromEncodedPoint; use k256::{AffinePoint, EncodedPoint, FieldBytes, Scalar}; use mpc_crypto::ScalarExt as _; use mpc_primitives::Signature; use mpc_primitives::{SignArgs, SignId, LATEST_MPC_KEY_VERSION}; use near_account_id::AccountId; -use sha3::{Digest, Keccak256}; use sp_core::crypto::{AccountId32 as SpAccountId32, Ss58AddressFormatRegistry, Ss58Codec}; use sp_core::{twox_128, H256}; use sp_runtime::traits::BlakeTwo256; @@ -128,21 +127,16 @@ pub struct HydrationSignatureRequestedEvent { impl SignatureEvent for HydrationSignatureRequestedEvent { fn generate_request_id(&self) -> [u8; 32] { - // Encode the event data in ABI format - let encoded = encode(&[ - Token::String(self.sender_string()), - Token::Bytes(self.payload.to_vec()), - Token::String(self.path.clone()), - Token::Uint(self.key_version.into()), - Token::String(self.chain_id.clone()), - Token::String(self.algo.clone()), - Token::String(self.dest.clone()), - Token::String(self.params.clone()), - ]); - // Calculate keccak256 hash - let mut hasher = Keccak256::new(); - hasher.update(&encoded); - hasher.finalize().into() + ethabi_request_id( + self.sender_string(), + self.payload, + self.path.clone(), + self.key_version, + self.chain_id.clone(), + self.algo.clone(), + self.dest.clone(), + self.params.clone(), + ) } fn generate_sign_request( @@ -566,7 +560,7 @@ pub async fn run( }; tracing::info!( "Hydration::Signet::SignBidirectionalRequested in block #{number} ({hash:?}): {:?}", - event + event ); let entropy = sp_core::hashing::blake2_256(ev.bytes()); @@ -872,3 +866,47 @@ fn value_to_vec_u8(v: &Value) -> Result> { other => Err(anyhow!("unsupported Vec shape: {other:?}")), } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn request_id_matches_ethabi() { + let event = HydrationSignatureRequestedEvent { + sender: [0xAA; 32], + payload: [0xBB; 32], + path: "m/44'/60'/0'/0/0".to_string(), + key_version: 3, + deposit: 999, + chain_id: "hydration-testnet".to_string(), + algo: "secp256k1".to_string(), + dest: "dest-address".to_string(), + params: "payload-params".to_string(), + }; + + let request_id = event.generate_request_id(); + let request_id_hex = hex::encode(request_id); + + // The expected request id encoded from ethabi: + // ``` + // let encoded = encode(&[ + // Token::String(self.sender_string()), + // Token::Bytes(self.payload.to_vec()), + // Token::String(self.path.clone()), + // Token::Uint(self.key_version.into()), + // Token::String(self.chain_id.clone()), + // Token::String(self.algo.clone()), + // Token::String(self.dest.clone()), + // Token::String(self.params.clone()), + // ]); + // let mut hasher = Keccak256::new(); + // hasher.update(&encoded); + // hasher.finalize().into() + // ``` + assert_eq!( + request_id_hex, + "67a3a9bf9d424d85bef21cf9780a0634c6a06061265ce9d1063f30f1eec84821" + ); + } +} diff --git a/chain-signatures/node/src/indexer_sol.rs b/chain-signatures/node/src/indexer_sol.rs index cf84a83ce..06fbd7f33 100644 --- a/chain-signatures/node/src/indexer_sol.rs +++ b/chain-signatures/node/src/indexer_sol.rs @@ -1,17 +1,16 @@ use crate::backlog::Backlog; +use crate::indexer_common::{ethabi_request_id, SignatureEvent, SignatureEventBox}; use crate::mesh::MeshState; use crate::node_client::NodeClient; use crate::protocol::{Chain, IndexedSignRequest, Sign, SignRequestType}; use crate::rpc::ContractStateWatcher; use crate::sign_bidirectional::hash_rlp_data; -use crate::indexer_common::{SignatureEvent, SignatureEventBox}; use alloy_sol_types::SolValue; use anchor_client::anchor_lang::AnchorDeserialize; use anchor_client::{Client, Cluster, Program}; use anchor_lang::solana_program::keccak; use anchor_lang::Discriminator; -use ethabi::{encode, Token}; use futures_util::StreamExt; use k256::elliptic_curve::sec1::FromEncodedPoint; use k256::{AffinePoint, Scalar}; @@ -20,7 +19,6 @@ use mpc_crypto::ScalarExt as _; use mpc_primitives::{SignArgs, SignId, LATEST_MPC_KEY_VERSION}; use near_account_id::AccountId; use serde::{Deserialize, Serialize}; -use sha3::{Digest, Keccak256}; use signet_program::{ RespondBidirectionalEvent, SignBidirectionalEvent, SignatureRequestedEvent, SignatureRespondedEvent, @@ -165,21 +163,16 @@ pub struct SolSignRequest { impl SignatureEvent for SignatureRequestedEvent { fn generate_request_id(&self) -> [u8; 32] { - // Encode the event data in ABI format - let encoded = encode(&[ - Token::String(self.sender.to_string()), - Token::Bytes(self.payload.to_vec()), - Token::String(self.path.clone()), - Token::Uint(self.key_version.into()), - Token::String(self.chain_id.clone()), - Token::String(self.algo.clone()), - Token::String(self.dest.clone()), - Token::String(self.params.clone()), - ]); - // Calculate keccak256 hash - let mut hasher = Keccak256::new(); - hasher.update(&encoded); - hasher.finalize().into() + ethabi_request_id( + self.sender_string(), + self.payload, + self.path.clone(), + self.key_version, + self.chain_id.clone(), + self.algo.clone(), + self.dest.clone(), + self.params.clone(), + ) } fn generate_sign_request( @@ -947,3 +940,48 @@ pub fn to_mpc_signature( recovery_id: sig.recovery_id, }) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn request_id_matches_ethabi() { + let event = SignatureRequestedEvent { + sender: Pubkey::new_from_array([0x11; 32]), + payload: [0x22; 32], + key_version: 7, + deposit: 12345, + chain_id: "solana-test-chain".to_string(), + path: "m/44'/501'/0'/0'".to_string(), + algo: "secp256k1".to_string(), + dest: "destination-address".to_string(), + params: "params-json".to_string(), + fee_payer: None, + }; + + let request_id = event.generate_request_id(); + let request_id_hex = hex::encode(request_id); + + // The expected request id encoded from ethabi: + // ``` + // let encoded = encode(&[ + // Token::String(self.sender_string()), + // Token::Bytes(self.payload.to_vec()), + // Token::String(self.path.clone()), + // Token::Uint(self.key_version.into()), + // Token::String(self.chain_id.clone()), + // Token::String(self.algo.clone()), + // Token::String(self.dest.clone()), + // Token::String(self.params.clone()), + // ]); + // let mut hasher = Keccak256::new(); + // hasher.update(&encoded); + // hasher.finalize().into() + // ``` + assert_eq!( + request_id_hex, + "7f7aee49c2a994cc17f85058f7e0b19a44603d619a7e738522f9aa329e457879" + ); + } +} diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 27980a60b..ecc149eb4 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -46,12 +46,12 @@ solana-transaction-status.workspace = true # crypto dependencies ecdsa = "0.16.9" -ethers-core.workspace = true -ethers = { version = "2.0.13", features = ["abigen"] } cait-sith = { git = "https://github.com/sig-net/cait-sith", rev = "9f34e8c", features = ["k256"] } elliptic-curve = { version = "0.13.5", default-features = false } k256 = { version = "0.13.1", features = ["sha256", "ecdsa", "serde"] } secp256k1.workspace = true +bip39 = "2" +bip32 = { version = "0.5", features = ["secp256k1"] } # near dependencies near-account-id.workspace = true diff --git a/integration-tests/src/actions/mod.rs b/integration-tests/src/actions/mod.rs index f72618c98..216d58901 100644 --- a/integration-tests/src/actions/mod.rs +++ b/integration-tests/src/actions/mod.rs @@ -6,7 +6,6 @@ use crate::cluster::Cluster; use anyhow::Context as _; use cait_sith::FullSignature; -use elliptic_curve::sec1::ToEncodedPoint; use k256::ecdsa::VerifyingKey; use k256::elliptic_curve::point::AffineCoordinates; use k256::elliptic_curve::sec1::FromEncodedPoint; @@ -27,11 +26,6 @@ use wait_for::{SignatureError, WaitForError}; use std::time::Duration; -use k256::{ - ecdsa::{Signature as RecoverableSignature, Signature as K256Signature}, - PublicKey as K256PublicKey, -}; - pub async fn request_batch_random_sign( nodes: &Cluster, ) -> anyhow::Result<(Vec<([u8; 32], [u8; 32])>, Account, AsyncTransactionStatus)> { @@ -156,82 +150,20 @@ pub fn x_coordinate(point: &C::AffinePoint) -> C::Scalar ::Uint>>::reduce_bytes(&point.x()) } -pub fn recover( - signature: ethers_core::types::Signature, - message: M, -) -> Result -where - M: Into, -{ - let message_hash = match message.into() { - ethers_core::types::RecoveryMessage::Data(ref message) => { - println!("identified as data"); - ethers_core::utils::hash_message(message) - } - ethers_core::types::RecoveryMessage::Hash(hash) => hash, - }; - println!("message_hash {message_hash:#?}"); - - let (recoverable_sig, recovery_id) = as_signature(signature)?; - let verifying_key = - VerifyingKey::recover_from_prehash(message_hash.as_ref(), &recoverable_sig, recovery_id)?; - println!("verifying_key {verifying_key:#?}"); - - let public_key = K256PublicKey::from(&verifying_key); - //println!("ethercore public key from verifying key {public_key:#?}"); - - let public_key = public_key.to_encoded_point(/* compress = */ false); - println!("ethercore recover encoded point pk {public_key:#?}"); - let public_key = public_key.as_bytes(); - debug_assert_eq!(public_key[0], 0x04); - let hash = ethers_core::utils::keccak256(&public_key[1..]); - let result = ethers_core::types::Address::from_slice(&hash[12..]); - println!("ethercore recover result {result:#?}"); - Ok(ethers_core::types::Address::from_slice(&hash[12..])) -} - -/// Retrieves the recovery signature. -fn as_signature( - signature: ethers_core::types::Signature, -) -> Result<(RecoverableSignature, k256::ecdsa::RecoveryId), ethers_core::types::SignatureError> { - let mut recovery_id = signature.recovery_id()?; - let mut signature = { - let mut r_bytes = [0u8; 32]; - let mut s_bytes = [0u8; 32]; - signature.r.to_big_endian(&mut r_bytes); - signature.s.to_big_endian(&mut s_bytes); - let gar: &generic_array::GenericArray = - generic_array::GenericArray::from_slice(&r_bytes); - let gas: &generic_array::GenericArray = - generic_array::GenericArray::from_slice(&s_bytes); - K256Signature::from_scalars(*gar, *gas)? - }; - - // Normalize into "low S" form. See: - // - https://github.com/RustCrypto/elliptic-curves/issues/988 - // - https://github.com/bluealloy/revm/pull/870 - if let Some(normalized) = signature.normalize_s() { - signature = normalized; - recovery_id = k256::ecdsa::RecoveryId::from_byte(recovery_id.to_byte() ^ 1).unwrap(); - } - - Ok((signature, recovery_id)) -} - -pub fn public_key_to_address(public_key: &secp256k1::PublicKey) -> ethers_core::types::Address { +pub fn public_key_to_address(public_key: &secp256k1::PublicKey) -> alloy::primitives::Address { let public_key = public_key.serialize_uncompressed(); debug_assert_eq!(public_key[0], 0x04); let hash: [u8; 32] = *alloy::primitives::keccak256(&public_key[1..]); - ethers_core::types::Address::from_slice(&hash[12..]) + alloy::primitives::Address::from_slice(&hash[12..]) } pub fn recover_eth_address( msg_hash: &[u8; 32], signature_bytes: &[u8; 64], recovery_id: u8, -) -> ethers_core::types::H160 { +) -> alloy::primitives::Address { let r = k256::Scalar::from_bytes(signature_bytes[..32].try_into().unwrap()).unwrap(); let s = k256::Scalar::from_bytes(signature_bytes[32..].try_into().unwrap()).unwrap(); let signature = k256::ecdsa::Signature::from_scalars(r, s).expect("valid r,s"); @@ -258,14 +190,12 @@ mod tests { use mpc_crypto::{derive_epsilon_near, derive_key, ScalarExt as _}; use mpc_primitives::LEGACY_MPC_KEY_VERSION_0; - use super::{public_key_to_address, recover, recover_eth_address, x_coordinate}; + use super::{public_key_to_address, recover_eth_address, x_coordinate}; // This test hardcodes the output of the signing process and checks that everything verifies as expected // If you find yourself changing the constants in this test you are likely breaking backwards compatibility #[test] fn signatures_havent_changed() { - const CHAIN_ID_ETH: u64 = 31337; - let big_r = "029b1b94bf4511b1a25986ba858cfa0fbdd5e4077c02e1d1102a194389b1f72df7"; let s = "25f3494bb7e7b3349a4b4d939d3e5ae1787a0863e4f698fb8ed2d3e11c195035"; let mpc_key = "045b4fa179e005361fd858f8a6f896d7afc23a53d3f95d6566a88cde954e7b2f1cb77c554705c35d4ffced67aeafbcda46d9d89d6f200c3a3d109f92872863b3dc"; @@ -354,26 +284,9 @@ mod tests { // let k256_verify_result = k256_verify_key.verify(&payload_hash_reversed, &k256_sig); // assert!(k256_verify_result.is_ok()); - // Check signature using etheres tooling - let ethers_r = ethers_core::types::U256::from_big_endian(r.to_bytes().as_slice()); - let ethers_s = ethers_core::types::U256::from_big_endian(s.to_bytes().as_slice()); - let ethers_v = to_eip155_v(multichain_sig.recovery_id, CHAIN_ID_ETH); - - let signature = ethers_core::types::Signature { - r: ethers_r, - s: ethers_s, - v: ethers_v, - }; - - let verifying_user_pk = ecdsa::VerifyingKey::from(&user_pk_k256); - let user_address_ethers: ethers_core::types::H160 = - ethers_core::utils::public_key_to_address(&verifying_user_pk); - - assert!(signature.verify(payload_hash, user_address_ethers).is_ok()); - // Check if recovered address is the same as the user address let signature_for_recovery: [u8; 64] = { - let mut signature = [0u8; 64]; // TODO: is there a better way to get these bytes? + let mut signature = [0u8; 64]; signature[..32].copy_from_slice(&r.to_bytes()); signature[32..].copy_from_slice(&s.to_bytes()); signature @@ -385,21 +298,6 @@ mod tests { multichain_sig.recovery_id, ); assert_eq!(user_address_from_pk, recovered_from_signature_address_web3); - - let recovered_from_signature_address_ethers = signature.recover(payload_hash).unwrap(); - assert_eq!( - user_address_from_pk, - recovered_from_signature_address_ethers - ); - - let recovered_from_signature_address_local_function = - recover(signature, payload_hash).unwrap(); - assert_eq!( - user_address_from_pk, - recovered_from_signature_address_local_function - ); - - assert_eq!(user_address_from_pk, user_address_ethers); } fn verify( @@ -463,8 +361,4 @@ mod tests { ) -> ProjectivePoint { (*x * k) + (*y * l) } - - pub fn to_eip155_v(recovery_id: u8, chain_id: u64) -> u64 { - (recovery_id as u64) + 35 + chain_id * 2 - } } diff --git a/integration-tests/src/actions/sign.rs b/integration-tests/src/actions/sign.rs index d667e50f8..7dc54dc0d 100644 --- a/integration-tests/src/actions/sign.rs +++ b/integration-tests/src/actions/sign.rs @@ -21,6 +21,7 @@ use k256::Secp256k1; use mpc_contract::errors; use mpc_contract::primitives::SignRequest; use mpc_crypto::ScalarExt as _; +use mpc_node::indexer_eth::abi::{ChainSignatures, SignatureRequestedEncoding}; use mpc_primitives::{SignId, Signature, LATEST_MPC_KEY_VERSION}; use near_crypto::InMemorySigner; use near_fetch::ops::AsyncTransactionStatus; @@ -44,65 +45,6 @@ use crate::containers; use signet_program::{RespondBidirectionalEvent, SignatureRespondedEvent}; -// ChainSignatures contract ABI -alloy::sol! { - #[sol(rpc)] - interface ChainSignatures { - struct SignRequest { - bytes32 payload; - string path; - uint32 keyVersion; - string algo; - string dest; - string params; - } - - struct AffinePoint { - uint256 x; - uint256 y; - } - - struct Signature { - AffinePoint bigR; - uint256 s; - uint8 recoveryId; - } - - function sign(SignRequest memory _request) external payable; - function getSignatureDeposit() external view returns (uint256); - - event SignatureRequested( - address indexed sender, - bytes32 payload, - uint32 keyVersion, - uint256 deposit, - uint256 chainId, - string path, - string algo, - string dest, - string params - ); - - event SignatureResponded( - bytes32 indexed requestId, - address indexed responder, - Signature signature - ); - } - - // Event encoding for request_id calculation - event SignatureRequestedEncoding( - address sender, - bytes payload, - string path, - uint32 keyVersion, - uint256 chainId, - string algo, - string dest, - string params - ); -} - pub const SIGN_GAS: Gas = Gas::from_tgas(50); pub const SIGN_DEPOSIT: NearToken = NearToken::from_yoctonear(1); diff --git a/integration-tests/src/containers.rs b/integration-tests/src/containers.rs index 30e57f9ce..45163e215 100644 --- a/integration-tests/src/containers.rs +++ b/integration-tests/src/containers.rs @@ -559,15 +559,17 @@ async fn wait_for_rpc(endpoint: &str) -> anyhow::Result<()> { } fn derive_secret_key(mnemonic: &str) -> anyhow::Result { - use ethers::signers::{coins_bip39::English, MnemonicBuilder}; + use bip32::{DerivationPath, XPrv}; + use bip39::Mnemonic; + use std::str::FromStr; - let wallet = MnemonicBuilder::::default() - .phrase(mnemonic) - .derivation_path("m/44'/60'/0'/0/0")? - .build()?; - let bytes = wallet.signer().to_bytes(); + let mnemonic = Mnemonic::parse(mnemonic)?; + let seed = mnemonic.to_seed(""); + let derivation_path = DerivationPath::from_str("m/44'/60'/0'/0/0")?; + let xprv = XPrv::derive_from_path(seed, &derivation_path)?; + let secret_key = xprv.private_key(); - Ok(format!("0x{}", hex::encode(bytes))) + Ok(format!("0x{}", hex::encode(secret_key.to_bytes()))) } fn shares_to_triples( diff --git a/integration-tests/src/eth.rs b/integration-tests/src/eth.rs index e067fdb77..f0f9eb11b 100644 --- a/integration-tests/src/eth.rs +++ b/integration-tests/src/eth.rs @@ -1,44 +1,76 @@ -use anyhow::Result; -use ethers::abi::{encode, Token}; -use ethers::contract::abigen; -use ethers::middleware::SignerMiddleware; -use ethers::providers::{Http, Provider}; -use ethers::signers::{LocalWallet, Signer}; -use ethers::types::{Address, H256, U256}; -use ethers::utils::keccak256; -use std::str::FromStr; -use std::sync::Arc; +use alloy::network::{Ethereum, EthereumWallet, TransactionBuilder}; +use alloy::primitives::{Address, B256, U256}; +use alloy::providers::Provider; +use alloy::providers::ProviderBuilder; +use alloy::rpc::types::request::TransactionRequest; +use alloy::signers::local::PrivateKeySigner; +use alloy::signers::Signer; +use alloy::sol_types::{SolEvent, SolValue}; +use anyhow::{Context, Result}; +use mpc_node::indexer_eth::abi::{ChainSignaturesConstructor, SignatureRequestedEncoding}; +use mpc_primitives::LATEST_MPC_KEY_VERSION; +use serde_json::Value; +use std::time::Duration; -abigen!( - ChainSignaturesContract, - "../chain-signatures/contract-eth/artifacts/contracts/ChainSignatures.sol/ChainSignatures.json" -); - -pub type SandboxMiddleware = SignerMiddleware, LocalWallet>; +pub use mpc_node::indexer_eth::abi::ChainSignatures; +pub use mpc_node::indexer_eth::abi::ChainSignatures::{SignRequest, SignatureResponded}; pub fn client( endpoint: &str, secret_key: &str, chain_id: u64, -) -> Result<(Arc, Address)> { - let provider = Provider::::try_from(endpoint)?; - let wallet = LocalWallet::from_str(secret_key)?; - let address = wallet.address(); - let wallet = wallet.with_chain_id(chain_id); - let client = Arc::new(SignerMiddleware::new(provider, wallet)); - Ok((client, address)) +) -> Result<(impl Provider + Clone + 'static, Address)> { + let signer: PrivateKeySigner = secret_key.parse()?; + let signer = signer.with_chain_id(Some(chain_id)); + let address = signer.address(); + let wallet = EthereumWallet::from(signer); + let provider = ProviderBuilder::new() + .wallet(wallet) + .connect_http(endpoint.parse()?); + Ok((provider, address)) } -pub async fn deploy_chain_signatures( - client: Arc, +pub async fn deploy_chain_signatures

( + client: P, + deployer_address: Address, mpc_address: Address, signature_deposit: U256, -) -> Result

{ - let contract = - ChainSignaturesContract::deploy(client.clone(), (mpc_address, signature_deposit))? - .send() - .await?; - Ok(contract.address()) +) -> Result
+where + P: Provider + Clone + Send + Sync + 'static, +{ + let artifact: Value = serde_json::from_slice(include_bytes!( + "../../chain-signatures/contract-eth/artifacts/contracts/ChainSignatures.sol/ChainSignatures.json" + ))?; + + let bytecode = artifact + .get("bytecode") + .and_then(Value::as_str) + .context("bytecode missing from artifact")?; + let mut deployment = hex::decode(bytecode.trim_start_matches("0x"))?; + + let constructor_args = ChainSignaturesConstructor { + mpcNetwork: mpc_address, + signatureDeposit: signature_deposit, + }; + deployment.extend_from_slice(&constructor_args.abi_encode()); + + let tx = >::with_input( + >::with_from( + >::into_create( + TransactionRequest::default(), + ), + deployer_address, + ), + deployment, + ); + + let pending = client.send_transaction(tx).await?; + let receipt = pending.get_receipt().await?; + let contract_address = receipt + .contract_address + .context("deployment receipt missing contract address")?; + Ok(contract_address) } #[allow(clippy::too_many_arguments)] @@ -51,20 +83,63 @@ pub fn compute_request_id( algo: &str, dest: &str, params: &str, -) -> H256 { - let tokens = vec![ - Token::Address(requester), - Token::Bytes(payload.to_vec()), - Token::String(path.to_string()), - Token::Uint(U256::from(key_version)), - Token::Uint(chain_id), - Token::String(algo.to_string()), - Token::String(dest.to_string()), - Token::String(params.to_string()), - ]; - H256::from(keccak256(encode(&tokens))) +) -> B256 { + let encoding = SignatureRequestedEncoding { + sender: requester, + payload: payload.to_vec().into(), + path: path.to_string(), + keyVersion: key_version, + chainId: chain_id, + algo: algo.to_string(), + dest: dest.to_string(), + params: params.to_string(), + }; + + alloy::primitives::keccak256(encoding.encode_data()) } -pub use chain_signatures_contract::{ - ChainSignaturesContract, ChainSignaturesContractEvents, SignRequest, SignatureRespondedFilter, -}; +pub async fn submit_sign_request

( + contract: &ChainSignatures::ChainSignaturesInstance

, + seed: usize, +) -> anyhow::Result<()> +where + P: Provider + Clone + Send + Sync + 'static, +{ + let payload = [seed as u8; 32]; + // The anvil RPC occasionally reports "nonce too low" even though we send + // sequentially and await receipts; retry once or twice to smooth out that + // transient behaviour. + const MAX_ATTEMPTS: usize = 3; + + for attempt in 1..=MAX_ATTEMPTS { + let request = SignRequest { + payload: payload.into(), + path: format!("offline_test_{seed}"), + keyVersion: LATEST_MPC_KEY_VERSION, + algo: "secp256k1".to_string(), + dest: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1".to_string(), + params: "{}".to_string(), + }; + + match contract.sign(request).value(U256::from(1_u64)).send().await { + Ok(pending) => { + pending.get_receipt().await?; + return Ok(()); + } + Err(err) => { + let err_msg = err.to_string(); + let is_nonce_race = err_msg.contains("nonce too low"); + + if is_nonce_race && attempt < MAX_ATTEMPTS { + tracing::warn!(attempt, "retrying ethereum sign after nonce too low"); + tokio::time::sleep(Duration::from_millis(200)).await; + continue; + } + + return Err(err.into()); + } + } + } + + Ok(()) +} diff --git a/integration-tests/src/lib.rs b/integration-tests/src/lib.rs index d0fbe1bcc..11f4e6c39 100644 --- a/integration-tests/src/lib.rs +++ b/integration-tests/src/lib.rs @@ -14,10 +14,10 @@ use std::time::Duration; use self::local::NodeEnvConfig; use crate::containers::DockerClient; +use alloy::primitives::{Address, U256}; use anyhow::Context as _; use cluster::spawner::ClusterSpawner; use deadpool_redis::Pool; -use ethers::types::{Address, U256}; use mpc_contract::config::{PresignatureConfig, ProtocolConfig, TripleConfig}; use mpc_contract::primitives::CandidateInfo; use mpc_node::gcp::GcpService; @@ -361,7 +361,8 @@ pub async fn setup(spawner: &mut ClusterSpawner) -> anyhow::Result { sandbox.chain_id, )?; let contract_address = - eth::deploy_chain_signatures(client, deployer_address, U256::zero()).await?; + eth::deploy_chain_signatures(client, deployer_address, deployer_address, U256::ZERO) + .await?; let rpc_endpoint = if cfg!(feature = "docker-test") { sandbox.internal_http_endpoint.clone() diff --git a/integration-tests/tests/cases/chains.rs b/integration-tests/tests/cases/chains.rs index 9db08c7df..e08a859f2 100644 --- a/integration-tests/tests/cases/chains.rs +++ b/integration-tests/tests/cases/chains.rs @@ -63,7 +63,7 @@ async fn test_solana_eth_bidirectional_flow() -> anyhow::Result<()> { let user_secp_pk = SecpPublicKey::from_slice(user_pk_bytes.as_bytes()) .context("failed to convert user public key")?; let user_address = actions::public_key_to_address(&user_secp_pk); - let user_alloy_address = AlloyAddress::from_slice(user_address.as_bytes()); + let user_alloy_address = AlloyAddress::from_slice(user_address.as_slice()); let legacy_tx = EthereumTransaction { nonce: U256::from(0u8), @@ -274,7 +274,7 @@ async fn ensure_eth_signer_funded( let secp = LibSecp256k1::signing_only(); let payer_pk = SecpPublicKey::from_secret_key(&secp, &payer_sk); let payer_address = actions::public_key_to_address(&payer_pk); - let payer_alloy = AlloyAddress::from_slice(payer_address.as_bytes()); + let payer_alloy = AlloyAddress::from_slice(payer_address.as_slice()); let signing_key = SigningKey::from_bytes(&payer_sk_array.into())?; let mut gas_price = fetch_gas_price(client, rpc_url).await?; diff --git a/integration-tests/tests/cases/ethereum.rs b/integration-tests/tests/cases/ethereum.rs index 46cc0f02c..6cdf07d83 100644 --- a/integration-tests/tests/cases/ethereum.rs +++ b/integration-tests/tests/cases/ethereum.rs @@ -1,5 +1,8 @@ +use alloy::primitives::U256; +use alloy::providers::Provider; +use alloy::rpc::types::Filter; +use alloy::sol_types::SolEvent; use anyhow::{anyhow, Context, Result}; -use ethers::types::{BlockNumber, U256}; use integration_tests::cluster::Cluster; use integration_tests::{actions, cluster, eth}; use k256::ecdsa::VerifyingKey; @@ -27,7 +30,7 @@ async fn test_signature_ethereum() -> Result<()> { let contract_address = eth_ctx.contract_address; let (client, requester) = eth::client(&endpoint, &secret_key, chain_id)?; - let contract = eth::ChainSignaturesContract::new(contract_address, client.clone()); + let contract = eth::ChainSignatures::new(contract_address, client.clone()); let payload = [7u8; 32]; let path = "test"; @@ -36,22 +39,24 @@ async fn test_signature_ethereum() -> Result<()> { let params = "{}"; let request = eth::SignRequest { - payload, + payload: payload.into(), path: path.to_string(), - key_version: LATEST_MPC_KEY_VERSION, + keyVersion: LATEST_MPC_KEY_VERSION, algo: algo.to_string(), dest: dest.to_string(), params: params.to_string(), }; - let call = contract.sign(request).value(U256::from(1_u64)); - let pending = call.send().await?; - let receipt = pending.await?.context("sign transaction failed")?; - let from_block = BlockNumber::Number( - receipt - .block_number - .context("missing block number in receipt")?, - ); + let pending = contract + .sign(request) + .to(contract_address) + .value(U256::from(1_u64)) + .send() + .await?; + let receipt = pending.get_receipt().await?; + let from_block = receipt + .block_number + .context("missing block number in receipt")?; let expected_request_id = eth::compute_request_id( requester, @@ -64,19 +69,38 @@ async fn test_signature_ethereum() -> Result<()> { params, ); + let signature_responded_topic = alloy::primitives::keccak256( + "SignatureResponded(bytes32,address,((uint256,uint256),uint256,uint8))", + ); + let mut matching_event = None; for _ in 0..30 { - let events = contract - .event::() + let latest_block = client.get_block_number().await?; + let filter = Filter::new() + .address(contract_address) .from_block(from_block) - .query() - .await?; - if let Some(event) = events.into_iter().find(|event| { - event.request_id == expected_request_id[..] && event.responder == requester + .to_block(latest_block) + .event_signature(signature_responded_topic); + + let events = client.get_logs(&filter).await?; + if let Some(found) = events.into_iter().find_map(|log| { + alloy::primitives::Log::new( + log.address(), + log.topics().to_vec(), + log.data().data.clone(), + ) + .and_then(|prim_log| { + eth::SignatureResponded::decode_log(&prim_log) + .ok() + .filter(|event| { + event.requestId == expected_request_id && event.responder == requester + }) + }) }) { - matching_event = Some(event); + matching_event = Some(found); break; } + tokio::time::sleep(Duration::from_secs(1)).await; } @@ -84,9 +108,9 @@ async fn test_signature_ethereum() -> Result<()> { matching_event.ok_or_else(|| anyhow!("did not observe signature response on ethereum"))?; let mut x_bytes = [0u8; 32]; - event.signature.big_r.x.to_big_endian(&mut x_bytes); + x_bytes.copy_from_slice(&event.signature.bigR.x.to_be_bytes::<32>()); let mut y_bytes = [0u8; 32]; - event.signature.big_r.y.to_big_endian(&mut y_bytes); + y_bytes.copy_from_slice(&event.signature.bigR.y.to_be_bytes::<32>()); let x_field: &FieldBytes = FieldBytes::from_slice(&x_bytes); let y_field: &FieldBytes = FieldBytes::from_slice(&y_bytes); let encoded_r = EncodedPoint::from_affine_coordinates(x_field, y_field, false); @@ -98,14 +122,14 @@ async fn test_signature_ethereum() -> Result<()> { let r_bytes = r_scalar.to_bytes(); let mut s_bytes = [0u8; 32]; - event.signature.s.to_big_endian(&mut s_bytes); + s_bytes.copy_from_slice(&event.signature.s.to_be_bytes::<32>()); let mut signature_bytes = [0u8; 64]; signature_bytes[..32].copy_from_slice(r_bytes.as_slice()); signature_bytes[32..].copy_from_slice(&s_bytes); let recovered_address = - actions::recover_eth_address(&payload, &signature_bytes, event.signature.recovery_id); + actions::recover_eth_address(&payload, &signature_bytes, event.signature.recoveryId); let network_public_key = cluster.root_public_key().await?; let mut network_pk = vec![0x04]; @@ -122,7 +146,10 @@ async fn test_signature_ethereum() -> Result<()> { let user_public_key = K256PublicKey::from_affine(user_affine) .map_err(|_| anyhow!("invalid derived public key"))?; let verifying_key = VerifyingKey::from(&user_public_key); - let expected_address = ethers::utils::public_key_to_address(&verifying_key); + let verifying_key = verifying_key.to_encoded_point(false); + let secp_public_key = + secp256k1::PublicKey::from_slice(verifying_key.as_bytes()).context("invalid secp key")?; + let expected_address = actions::public_key_to_address(&secp_public_key); anyhow::ensure!( recovered_address == expected_address, @@ -149,7 +176,7 @@ async fn test_proper_indexer_checkpoint() -> Result<()> { let contract_address = eth_ctx.contract_address; let (client, requester) = eth::client(&endpoint, &secret_key, chain_id)?; - let contract = eth::ChainSignaturesContract::new(contract_address, client.clone()); + let contract = eth::ChainSignatures::new(contract_address, client.clone()); // Get initial checkpoint state let node_idx = 0; @@ -168,22 +195,24 @@ async fn test_proper_indexer_checkpoint() -> Result<()> { let params = "{}"; let request = eth::SignRequest { - payload, + payload: payload.into(), path: path.to_string(), - key_version: LATEST_MPC_KEY_VERSION, + keyVersion: LATEST_MPC_KEY_VERSION, algo: algo.to_string(), dest: dest.to_string(), params: params.to_string(), }; - let call = contract.sign(request).value(U256::from(1_u64)); - let pending = call.send().await?; - let receipt = pending.await?.context("sign transaction failed")?; - let from_block = BlockNumber::Number( - receipt - .block_number - .context("missing block number in receipt")?, - ); + let pending = contract + .sign(request) + .to(contract_address) + .value(U256::from(1_u64)) + .send() + .await?; + let receipt = pending.get_receipt().await?; + let from_block = receipt + .block_number + .context("missing block number in receipt")?; let expected_request_id = eth::compute_request_id( requester, @@ -214,19 +243,38 @@ async fn test_proper_indexer_checkpoint() -> Result<()> { ); // Wait for the signature response + let signature_responded_topic = alloy::primitives::keccak256( + "SignatureResponded(bytes32,address,((uint256,uint256),uint256,uint8))", + ); + let mut matching_event = None; for _ in 0..30 { - let events = contract - .event::() + let latest_block = client.get_block_number().await?; + let filter = Filter::new() + .address(contract_address) .from_block(from_block) - .query() - .await?; - if let Some(event) = events.into_iter().find(|event| { - event.request_id == expected_request_id[..] && event.responder == requester + .to_block(latest_block) + .event_signature(signature_responded_topic); + + let events = client.get_logs(&filter).await?; + if let Some(found) = events.into_iter().find_map(|log| { + alloy::primitives::Log::new( + log.address(), + log.topics().to_vec(), + log.data().data.clone(), + ) + .and_then(|prim_log| { + eth::SignatureResponded::decode_log(&prim_log) + .ok() + .filter(|event| { + event.requestId == expected_request_id && event.responder == requester + }) + }) }) { - matching_event = Some(event); + matching_event = Some(found); break; } + tokio::time::sleep(Duration::from_secs(1)).await; } @@ -251,11 +299,11 @@ async fn test_proper_indexer_checkpoint() -> Result<()> { "pending transactions count after response" ); - let expected_request_bytes = expected_request_id.as_bytes(); + let expected_request_bytes: [u8; 32] = expected_request_id.into(); let request_still_present = checkpoint .pending_requests .iter() - .any(|tx| tx.sign_id.request_id == *expected_request_bytes); + .any(|tx| tx.sign_id.request_id == expected_request_bytes); assert!( !request_still_present, @@ -283,11 +331,11 @@ async fn test_checkpoint_recovery_after_offline() -> anyhow::Result<()> { ð_ctx.sandbox.secret_key, eth_ctx.sandbox.chain_id, )?; - let eth_contract = eth::ChainSignaturesContract::new(eth_ctx.contract_address, eth_client); + let eth_contract = eth::ChainSignatures::new(eth_ctx.contract_address, eth_client); // Produce a few sign requests up front so nodes create initial checkpoints for i in 0..5 { - submit_eth_sign_request(ð_contract, i).await?; + eth::submit_sign_request(ð_contract, i).await?; } let active_idx = 1usize; @@ -312,7 +360,7 @@ async fn test_checkpoint_recovery_after_offline() -> anyhow::Result<()> { let mut elapsed = Duration::default(); let mut seed = 100usize; while elapsed < offline_duration { - submit_eth_sign_request(ð_contract, seed).await?; + eth::submit_sign_request(ð_contract, seed).await?; seed += 1; tokio::time::sleep(Duration::from_secs(2)).await; elapsed += Duration::from_secs(2); @@ -375,31 +423,6 @@ async fn test_checkpoint_recovery_after_offline() -> anyhow::Result<()> { Ok(()) } -async fn submit_eth_sign_request( - contract: ð::ChainSignaturesContract, - seed: usize, -) -> anyhow::Result<()> { - let payload = [seed as u8; 32]; - let request = eth::SignRequest { - payload, - path: format!("offline_test_{seed}"), - key_version: LATEST_MPC_KEY_VERSION, - algo: "secp256k1".to_string(), - dest: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1".to_string(), - params: "{}".to_string(), - }; - - contract - .sign(request) - .value(U256::from(1_u64)) - .send() - .await? - .await? - .context("sign transaction failed")?; - - Ok(()) -} - async fn wait_node_checkpoint( nodes: &Cluster, node_idx: usize,