diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..5b59dd3 Binary files /dev/null and b/.DS_Store differ diff --git a/Cargo.lock b/Cargo.lock index 64a52bd..80d78ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,15 +49,46 @@ name = "alloy-consensus" version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy.git?rev=d68a6b7#d68a6b787b2904061f0ae7fcc02ece8513e3c500" dependencies = [ - "alloy-eips", + "alloy-eips 0.1.0", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 0.1.0", "c-kzg", "serde", "sha2", ] +[[package]] +name = "alloy-consensus" +version = "0.2.0" +source = "git+https://github.com/alloy-rs/alloy.git#67f024a0220451f36535ad427f9c6af88312fe8c" +dependencies = [ + "alloy-eips 0.2.0", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.2.0", + "c-kzg", + "serde", +] + +[[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", + "alloy-sol-type-parser", + "alloy-sol-types", + "const-hex", + "derive_more", + "itoa", + "serde", + "serde_json", + "winnow 0.6.15", +] + [[package]] name = "alloy-eips" version = "0.1.0" @@ -65,10 +96,24 @@ source = "git+https://github.com/alloy-rs/alloy.git?rev=d68a6b7#d68a6b787b290406 dependencies = [ "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 0.1.0", + "c-kzg", + "once_cell", + "serde", +] + +[[package]] +name = "alloy-eips" +version = "0.2.0" +source = "git+https://github.com/alloy-rs/alloy.git#67f024a0220451f36535ad427f9c6af88312fe8c" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.2.0", "c-kzg", "once_cell", "serde", + "sha2", ] [[package]] @@ -77,10 +122,22 @@ version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy.git?rev=d68a6b7#d68a6b787b2904061f0ae7fcc02ece8513e3c500" dependencies = [ "alloy-primitives", - "alloy-serde", + "alloy-serde 0.1.0", "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", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + [[package]] name = "alloy-json-rpc" version = "0.1.0" @@ -93,22 +150,53 @@ dependencies = [ "tracing", ] +[[package]] +name = "alloy-json-rpc" +version = "0.2.0" +source = "git+https://github.com/alloy-rs/alloy.git#67f024a0220451f36535ad427f9c6af88312fe8c" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", + "thiserror", + "tracing", +] + [[package]] name = "alloy-network" version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy.git?rev=d68a6b7#d68a6b787b2904061f0ae7fcc02ece8513e3c500" dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-json-rpc", + "alloy-consensus 0.1.0", + "alloy-eips 0.1.0", + "alloy-json-rpc 0.1.0", "alloy-primitives", "alloy-rpc-types", - "alloy-signer", + "alloy-signer 0.1.0", "async-trait", "futures-utils-wasm", "thiserror", ] +[[package]] +name = "alloy-network" +version = "0.2.0" +source = "git+https://github.com/alloy-rs/alloy.git#67f024a0220451f36535ad427f9c6af88312fe8c" +dependencies = [ + "alloy-consensus 0.2.0", + "alloy-eips 0.2.0", + "alloy-json-rpc 0.2.0", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde 0.2.0", + "alloy-signer 0.2.0", + "alloy-sol-types", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "thiserror", +] + [[package]] name = "alloy-node-bindings" version = "0.1.0" @@ -151,9 +239,9 @@ name = "alloy-provider" version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy.git?rev=d68a6b7#d68a6b787b2904061f0ae7fcc02ece8513e3c500" dependencies = [ - "alloy-eips", - "alloy-json-rpc", - "alloy-network", + "alloy-eips 0.1.0", + "alloy-json-rpc 0.1.0", + "alloy-network 0.1.0", "alloy-primitives", "alloy-rpc-client", "alloy-rpc-types", @@ -193,7 +281,7 @@ checksum = "d83524c1f6162fcb5b0decf775498a125066c86dda6066ed609531b0e912f85a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -201,7 +289,7 @@ name = "alloy-rpc-client" version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy.git?rev=d68a6b7#d68a6b787b2904061f0ae7fcc02ece8513e3c500" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.1.0", "alloy-transport", "alloy-transport-http", "futures", @@ -221,12 +309,12 @@ name = "alloy-rpc-types" version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy.git?rev=d68a6b7#d68a6b787b2904061f0ae7fcc02ece8513e3c500" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 0.1.0", + "alloy-eips 0.1.0", "alloy-genesis", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 0.1.0", "alloy-sol-types", "itertools 0.12.1", "serde", @@ -234,6 +322,23 @@ dependencies = [ "thiserror", ] +[[package]] +name = "alloy-rpc-types-eth" +version = "0.2.0" +source = "git+https://github.com/alloy-rs/alloy.git#67f024a0220451f36535ad427f9c6af88312fe8c" +dependencies = [ + "alloy-consensus 0.2.0", + "alloy-eips 0.2.0", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 0.2.0", + "alloy-sol-types", + "itertools 0.13.0", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "alloy-rpc-types-trace" version = "0.1.0" @@ -241,7 +346,7 @@ source = "git+https://github.com/alloy-rs/alloy.git?rev=d68a6b7#d68a6b787b290406 dependencies = [ "alloy-primitives", "alloy-rpc-types", - "alloy-serde", + "alloy-serde 0.1.0", "serde", "serde_json", ] @@ -256,6 +361,16 @@ dependencies = [ "serde_json", ] +[[package]] +name = "alloy-serde" +version = "0.2.0" +source = "git+https://github.com/alloy-rs/alloy.git#67f024a0220451f36535ad427f9c6af88312fe8c" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + [[package]] name = "alloy-signer" version = "0.1.0" @@ -269,6 +384,36 @@ dependencies = [ "thiserror", ] +[[package]] +name = "alloy-signer" +version = "0.2.0" +source = "git+https://github.com/alloy-rs/alloy.git#67f024a0220451f36535ad427f9c6af88312fe8c" +dependencies = [ + "alloy-dyn-abi", + "alloy-primitives", + "alloy-sol-types", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror", +] + +[[package]] +name = "alloy-signer-local" +version = "0.2.0" +source = "git+https://github.com/alloy-rs/alloy.git#67f024a0220451f36535ad427f9c6af88312fe8c" +dependencies = [ + "alloy-consensus 0.2.0", + "alloy-network 0.2.0", + "alloy-primitives", + "alloy-signer 0.2.0", + "async-trait", + "k256", + "rand", + "thiserror", +] + [[package]] name = "alloy-sol-macro" version = "0.7.7" @@ -280,7 +425,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -292,11 +437,11 @@ dependencies = [ "alloy-sol-macro-input", "const-hex", "heck", - "indexmap", + "indexmap 2.2.6", "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", "syn-solidity", "tiny-keccak", ] @@ -312,10 +457,20 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", "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 0.6.15", +] + [[package]] name = "alloy-sol-types" version = "0.7.7" @@ -333,7 +488,7 @@ name = "alloy-transport" version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy.git?rev=d68a6b7#d68a6b787b2904061f0ae7fcc02ece8513e3c500" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.1.0", "base64", "futures-util", "futures-utils-wasm", @@ -351,7 +506,7 @@ name = "alloy-transport-http" version = "0.1.0" source = "git+https://github.com/alloy-rs/alloy.git?rev=d68a6b7#d68a6b787b2904061f0ae7fcc02ece8513e3c500" dependencies = [ - "alloy-json-rpc", + "alloy-json-rpc 0.1.0", "alloy-transport", "reqwest", "serde_json", @@ -508,7 +663,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -519,7 +674,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -530,7 +685,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -675,9 +830,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" [[package]] name = "cfg-if" @@ -770,7 +925,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core 0.9.10", @@ -807,7 +962,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.0", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -905,6 +1060,50 @@ dependencies = [ "windows-sys 0.52.0", ] +[[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-rlp", + "impl-serde", + "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-rlp", + "impl-serde", + "primitive-types", + "uint", +] + [[package]] name = "fastrand" version = "2.1.0" @@ -1036,7 +1235,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -1120,6 +1319,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.14.5" @@ -1267,6 +1472,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.5.0" @@ -1286,6 +1502,24 @@ dependencies = [ "parity-scale-codec", ] +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + [[package]] name = "impl-trait-for-tuples" version = "0.2.2" @@ -1297,6 +1531,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.2.6" @@ -1304,7 +1548,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.5", ] [[package]] @@ -1351,6 +1595,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -1380,6 +1633,15 @@ dependencies = [ "signature", ] +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + [[package]] name = "keccak-asm" version = "0.1.1" @@ -1436,9 +1698,15 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" dependencies = [ - "hashbrown", + "hashbrown 0.14.5", ] +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + [[package]] name = "memchr" version = "2.7.4" @@ -1544,9 +1812,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.64" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -1565,7 +1833,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -1576,9 +1844,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -1690,7 +1958,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -1735,6 +2003,8 @@ checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", + "impl-rlp", + "impl-serde", "uint", ] @@ -2166,7 +2436,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -2225,6 +2495,16 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + [[package]] name = "sha3-asm" version = "0.1.1" @@ -2239,23 +2519,33 @@ dependencies = [ name = "sig_verifier" version = "0.1.0" dependencies = [ - "alloy-json-rpc", + "alloy-dyn-abi", + "alloy-json-rpc 0.1.0", "alloy-node-bindings", "alloy-primitives", "alloy-provider", "alloy-rpc-types", + "alloy-signer 0.2.0", + "alloy-signer-local", "alloy-sol-types", "alloy-transport", "byteorder", "env_logger", + "ethabi", + "ethereum-types", + "indexmap 1.9.3", + "itertools 0.10.5", "k256", "log", "rand", "regex", + "rustc-hex", + "serde", "serde_json", "serial_test", "thiserror", "tokio", + "validator", "zerocopy 0.3.2", ] @@ -2338,9 +2628,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.71" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -2356,7 +2646,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -2421,7 +2711,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -2482,7 +2772,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -2532,9 +2822,9 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap", + "indexmap 2.2.6", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -2585,7 +2875,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -2667,10 +2957,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", - "idna", + "idna 0.5.0", "percent-encoding", ] +[[package]] +name = "validator" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d6937c33ec6039d8071bcf72933146b5bbe378d645d8fa59bdadabfc2a249" +dependencies = [ + "idna 0.2.3", + "lazy_static", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_types", +] + +[[package]] +name = "validator_types" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9680608df133af2c1ddd5eaf1ddce91d60d61b6bc51494ef326458365a470a" + [[package]] name = "valuable" version = "0.1.0" @@ -2734,7 +3046,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", "wasm-bindgen-shared", ] @@ -2768,7 +3080,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2968,6 +3280,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.52.0" @@ -3025,7 +3346,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -3045,5 +3366,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] diff --git a/Cargo.toml b/Cargo.toml index adb0819..79e6216 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,13 +10,25 @@ alloy-json-rpc = { git = "https://github.com/alloy-rs/alloy.git", rev = "d68a6b7 alloy-primitives = { version = "0.7.0" } alloy-provider = { git = "https://github.com/alloy-rs/alloy.git", rev = "d68a6b7" } alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy.git", rev = "d68a6b7" } -alloy-sol-types = { version = "0.7.0" } +alloy-sol-types = { version = "0.7.0", features=["std"] } alloy-transport = { git = "https://github.com/alloy-rs/alloy.git", rev = "d68a6b7" } +alloy-signer = { git = "https://github.com/alloy-rs/alloy.git" } +alloy-dyn-abi = { version = "0.7.0" , features=["std", "eip712"] } +alloy-signer-local = {git = "https://github.com/alloy-rs/alloy.git"} k256 = "0.13" log = "0.4" thiserror = "1.0.63" byteorder = "1.4" zerocopy = "0.3" +serde_json = "1" +serde = { version = "1.0", features = ["derive"] } +# eip-712 = "0.1.1" +ethabi = "18.0.0" +ethereum-types = "0.14.1" +itertools = "0.10.0" +indexmap = "1.7.0" +rustc-hex = "2.1.0" +validator = "0.12.0" [dev-dependencies] alloy-node-bindings = { git = "https://github.com/alloy-rs/alloy.git", rev = "d68a6b7" } @@ -30,3 +42,6 @@ serial_test = "0.5.1" [build-dependencies] alloy-primitives = { version = "0.7.0" } serde_json = "1" + +[features] +eip712 = ["alloy-signer/eip712"] \ No newline at end of file diff --git a/README.md b/README.md index e2824b5..d0b320a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# Universal Etheruem signature verification with ERC-6492 +# Universal Etheruem signature verification with ERC-6942 This crate verifies any Ethereum signature including: - EOAs - Smart contract wallets with [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271) -- Predeploy contract wallets with [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492) +- Predeploy contract wallets with [ERC-6942](https://eips.ethereum.org/EIPS/eip-6942) ## Usage diff --git a/build.rs b/build.rs index bb533b4..bf3fb09 100644 --- a/build.rs +++ b/build.rs @@ -73,14 +73,14 @@ fn compile_contracts() { assert!(output.status.success()); } -const ERC6492_FILE: &str = "forge/out/Erc6492.sol/ValidateSigOffchain.json"; -const ERC6492_BYTECODE_FILE: &str = "forge/out/Erc6492.sol/ValidateSigOffchain.bytecode"; +const ERC6942_FILE: &str = "forge/out/Erc6942.sol/ValidateSigOffchain.json"; +const ERC6942_BYTECODE_FILE: &str = "forge/out/Erc6942.sol/ValidateSigOffchain.bytecode"; const ERC1271_MOCK_FILE: &str = "forge/out/Erc1271Mock.sol/Erc1271Mock.json"; const ERC1271_MOCK_BYTECODE_FILE: &str = "forge/out/Erc1271Mock.sol/Erc1271Mock.bytecode"; fn extract_bytecodes() { extract_bytecode( - &format_foundry_dir(ERC6492_FILE), - &format_foundry_dir(ERC6492_BYTECODE_FILE), + &format_foundry_dir(ERC6942_FILE), + &format_foundry_dir(ERC6942_BYTECODE_FILE), ); extract_bytecode( &format_foundry_dir(ERC1271_MOCK_FILE), diff --git a/contracts/Erc6492.sol b/contracts/Erc6942.sol similarity index 90% rename from contracts/Erc6492.sol rename to contracts/Erc6942.sol index 41586fe..7b3c458 100644 --- a/contracts/Erc6492.sol +++ b/contracts/Erc6942.sol @@ -4,10 +4,10 @@ interface IERC1271Wallet { } error ERC1271Revert(bytes error); -error ERC6492DeployFailed(bytes error); +error ERC6942DeployFailed(bytes error); contract UniversalSigValidator { - bytes32 private constant ERC6492_DETECTION_SUFFIX = 0x6492649264926492649264926492649264926492649264926492649264926492; + bytes32 private constant ERC6942_DETECTION_SUFFIX = 0x6942694269426942694269426942694269426942694269426942694269426942; bytes4 private constant ERC1271_SUCCESS = 0x1626ba7e; function isValidSigImpl( @@ -19,11 +19,11 @@ contract UniversalSigValidator { ) public returns (bool) { uint contractCodeLen = address(_signer).code.length; bytes memory sigToValidate; - // The order here is strictly defined in https://eips.ethereum.org/EIPS/eip-6492 - // - ERC-6492 suffix check and verification first, while being permissive in case the contract is already deployed; if the contract is deployed we will check the sig against the deployed version, this allows 6492 signatures to still be validated while taking into account potential key rotation + // The order here is strictly defined in https://eips.ethereum.org/EIPS/eip-6942 + // - ERC-6942 suffix check and verification first, while being permissive in case the contract is already deployed; if the contract is deployed we will check the sig against the deployed version, this allows 6942 signatures to still be validated while taking into account potential key rotation // - ERC-1271 verification if there's contract code // - finally, ecrecover - bool isCounterfactual = bytes32(_signature[_signature.length-32:_signature.length]) == ERC6492_DETECTION_SUFFIX; + bool isCounterfactual = bytes32(_signature[_signature.length-32:_signature.length]) == ERC6942_DETECTION_SUFFIX; if (isCounterfactual) { address create2Factory; bytes memory factoryCalldata; @@ -31,7 +31,7 @@ contract UniversalSigValidator { if (contractCodeLen == 0 || tryPrepare) { (bool success, bytes memory err) = create2Factory.call(factoryCalldata); - if (!success) revert ERC6492DeployFailed(err); + if (!success) revert ERC6942DeployFailed(err); } } else { sigToValidate = _signature; diff --git a/src/lib.rs b/src/lib.rs index 7cecd1c..67a8056 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ use { - alloy_primitives::{eip191_hash_message, keccak256, Address, Bytes, B256, U256}, + alloy_primitives::{keccak256, Address, Bytes, FixedBytes, B256, U256}, alloy_provider::Provider, alloy_rpc_types::{BlockId, TransactionInput, TransactionRequest}, alloy_sol_types::{sol, SolConstructor}, @@ -11,25 +11,26 @@ use { /// The expected result for a successful signature verification. const SUCCESS_RESULT: u8 = 0x01; -/// The magic bytes used to detect ERC-6492 signatures. -const ERC6492_DETECTION_SUFFIX: [u8; 32] = [ +/// The magic bytes used to detect ERC-6942 signatures. +const ERC6942_DETECTION_SUFFIX: [u8; 32] = [ 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, 0x64, 0x92, ]; const VALIDATE_SIG_OFFCHAIN_BYTECODE: &[u8] = include_bytes!(concat!( env!("OUT_DIR"), - "/../../../../.foundry/forge/out/Erc6492.sol/ValidateSigOffchain.bytecode" + "/../../../../.foundry/forge/out/Erc6942.sol/ValidateSigOffchain.bytecode" )); sol! { contract ValidateSigOffchain { constructor (address _signer, bytes32 _hash, bytes memory _signature); + function isValidSig(address _signer, bytes32 _hash, bytes memory _signature) external view returns (bool); } } sol! { - struct ERC6492SignatureData { + struct ERC6942SignatureData { address create2_factory; bytes factory_calldata; bytes signature; @@ -41,7 +42,7 @@ sol! { } sol! { - struct ERC6492Signature { + struct ERC6942Signature { address create2_factory; bytes factory_calldata; bytes signature; @@ -78,16 +79,16 @@ pub enum SignatureError { pub type RpcError = alloy_json_rpc::RpcError; -// Parses an ERC-6492 signature into its components. +// Parses an ERC-6942 signature into its components. // // # Arguments // -// * `sig_data` - The ERC-6492 signature data to parse. +// * `sig_data` - The ERC-6942 signature data to parse. // // # Returns // // A tuple containing the CREATE2 factory address, factory calldata, and the original signature. -fn parse_erc6492_signature(sig_data: &[u8]) -> Result<(Address, Vec, Vec), SignatureError> { +fn parse_erc6942_signature(sig_data: &[u8]) -> Result<(Address, Vec, Vec), SignatureError> { if sig_data.len() < 96 { return Err(SignatureError::InvalidSignature); } @@ -117,7 +118,6 @@ fn parse_erc6492_signature(sig_data: &[u8]) -> Result<(Address, Vec, Vec Ok((create2_factory, factory_calldata, signature)) } - // Converts a byte slice to a usize. fn bytes_to_usize(bytes: &[u8]) -> usize { let mut padded = [0u8; 32]; @@ -128,7 +128,7 @@ fn bytes_to_usize(bytes: &[u8]) -> usize { /// Extracts the signer's address from a signature. /// -/// This function supports EOA, ERC-1271, and ERC-6492 signatures. +/// This function supports EOA, ERC-1271, and ERC-6942 signatures. /// /// # Arguments /// @@ -139,23 +139,22 @@ fn bytes_to_usize(bytes: &[u8]) -> usize { /// # Returns /// /// The extracted address or an error if the extraction fails. -pub async fn extract_address( +pub async fn extract_address( signature: S, - message: M, + message: FixedBytes<32>, provider: P, ) -> Result where S: Into, - M: AsRef<[u8]>, P: Provider, T: Transport + Clone, { let signature: Bytes = signature.into(); - let message_hash = eip191_hash_message(message); - if signature.len() >= 32 && signature[signature.len() - 32..] == ERC6492_DETECTION_SUFFIX { + if signature.len() >= 32 && signature[signature.len() - 32..] == ERC6942_DETECTION_SUFFIX { let sig_data = &signature[..signature.len() - 32]; - let (create2_factory, factory_calldata, _) = parse_erc6492_signature(sig_data)?; + let (create2_factory, factory_calldata, original_signature) = + parse_erc6942_signature(sig_data)?; let tx = TransactionRequest { to: Some(create2_factory), @@ -169,14 +168,13 @@ where .map_err(SignatureError::ProviderError)?; if result.len() < 20 { - return Err(SignatureError::InvalidSignature); + // If the contract is already deployed, we should fall back to standard signature verification + return ecrecover_address(message, &original_signature); } + Ok(Address::from_slice(&result[result.len() - 20..])) } else if signature.len() == 65 { - let v = signature[64]; - let r = U256::from_be_bytes::<32>(signature[0..32].try_into().unwrap()); - let s = U256::from_be_bytes::<32>(signature[32..64].try_into().unwrap()); - ecrecover(message_hash, v, r, s) + ecrecover_address(message, &signature) } else { if signature.len() < 20 { return Err(SignatureError::InvalidSignature); @@ -185,6 +183,18 @@ where } } +fn ecrecover_address(message: FixedBytes<32>, signature: &[u8]) -> Result { + if signature.len() != 65 { + return Err(SignatureError::InvalidSignature); + } + + let v = signature[64]; + let r = U256::from_be_bytes::<32>(signature[0..32].try_into().unwrap()); + let s = U256::from_be_bytes::<32>(signature[32..64].try_into().unwrap()); + + ecrecover(B256::from(message), v, r, s) +} + /// Verifies a signature automatically by extracting the signer's address. /// /// This function first extracts the signer's address from the signature and then @@ -201,12 +211,12 @@ where /// A `Verification` enum indicating whether the signature is valid or invalid. pub async fn verify_signature_auto( signature: S, - message: M, + message: FixedBytes<32>, provider: P, ) -> Result where S: Into + Clone, - M: AsRef<[u8]> + Clone, + // M: AsRef<[u8]> + Clone, P: Provider, T: Transport + Clone, { @@ -250,7 +260,7 @@ fn ecrecover(hash: B256, v: u8, r: U256, s: U256) -> Result Result( +pub async fn verify_signature( signature: S, address: Address, - message: M, + message: FixedBytes<32>, provider: P, ) -> Result where S: Into, - M: AsRef<[u8]>, P: Provider, T: Transport + Clone, { let call = ValidateSigOffchain::constructorCall { _signer: address, - _hash: eip191_hash_message(message), + _hash: message, _signature: signature.into(), }; let bytes = VALIDATE_SIG_OFFCHAIN_BYTECODE @@ -325,15 +334,19 @@ mod test_helpers; mod test { use { super::*, - alloy_primitives::{address, b256, bytes, hex, Uint, B256, U256}, + alloy_dyn_abi::eip712::TypedData, + alloy_primitives::{address, b256, bytes, keccak256, Address, Uint, B256, I256, U256}, alloy_provider::{network::Ethereum, ReqwestProvider}, - alloy_sol_types::{Eip712Domain, SolCall, SolValue}, + alloy_signer::{Signer, SignerSync}, + alloy_signer_local::PrivateKeySigner, + alloy_sol_types::{eip712_domain, sol, SolCall, SolValue}, k256::ecdsa::SigningKey, + serde::Serialize, serial_test::serial, test_helpers::{ - deploy_contract, sign_message, spawn_anvil, CREATE2_CONTRACT, ERC1271_MOCK_CONTRACT, + deploy_contract, message_str_to_bytes, sign_message_eip191, spawn_anvil, + CREATE2_CONTRACT, ERC1271_MOCK_CONTRACT, }, - zerocopy::AsBytes, }; // Manual test. Paste address, signature, message, and project ID to verify @@ -350,10 +363,13 @@ mod test { .parse() .unwrap(), ); - assert!(verify_signature(signature, address, message, provider) - .await - .unwrap() - .is_valid()); + let message_bytes = message_str_to_bytes(message); + assert!( + verify_signature(signature, address, message_bytes, provider) + .await + .unwrap() + .is_valid() + ); } #[tokio::test] @@ -361,14 +377,64 @@ mod test { async fn test_extract_address_eoa() { let (_anvil, _rpc_url, provider, private_key) = spawn_anvil(); let message = "test message"; - let signature = sign_message(message, &private_key); + let message_bytes = alloy_primitives::eip191_hash_message(message.as_bytes()); + let signature = sign_message_eip191(message, &private_key); let expected_address = Address::from_private_key(&private_key); - let extracted_address = extract_address(signature.clone(), message, provider.clone()) + let extracted_address = extract_address(signature.clone(), message_bytes, provider.clone()) .await .unwrap(); assert_eq!(extracted_address, expected_address); } + #[tokio::test] + #[serial] + async fn test_extract_address_eip721() { + let (_anvil, _rpc_url, provider, _private_key) = spawn_anvil(); + sol! { + #[derive(Debug, Serialize)] + struct FooBar { + int256 foo; + uint256 bar; + bytes fizz; + bytes32 buzz; + string far; + address out; + } + } + + let signer = PrivateKeySigner::random(); + + let chain_id = provider.get_chain_id().await.unwrap(); + let signer = signer.with_chain_id(Some(chain_id)); + + let domain = eip712_domain! { + name: "Eip712Test", + version: "1", + chain_id: chain_id, + verifying_contract: signer.address(), + salt: keccak256("eip712-test-75F0CCte"), + }; + let foo_bar = FooBar { + foo: I256::try_from(10u64).unwrap(), + bar: U256::from(20u64), + fizz: b"fizz".to_vec().into(), + buzz: keccak256("buzz"), + far: "space".into(), + out: Address::ZERO, + }; + + let foo_bar_dynamic = TypedData::from_struct(&foo_bar, Some(domain.clone())); + let dynamic_hash = foo_bar_dynamic.eip712_signing_hash().unwrap(); + let sig_dynamic = signer.sign_hash_sync(&dynamic_hash).unwrap(); + let signature: Bytes = sig_dynamic.as_bytes().to_vec().into(); + + let extracted_address = extract_address(signature, dynamic_hash, provider) + .await + .unwrap(); + + assert_eq!(extracted_address, signer.address()); + } + #[tokio::test] #[serial] async fn test_extract_address_erc1271() { @@ -381,68 +447,50 @@ mod test { ) .await; let message = "test message"; - let signature = sign_message(message, &private_key); + let message_bytes = message_str_to_bytes(message); + let signature = sign_message_eip191(message, &private_key); // Use the raw bytes of the Address let erc1271_signature = [contract_address.as_slice(), signature.as_ref()].concat(); - let extracted_address = extract_address(erc1271_signature, message, provider.clone()) + let extracted_address = extract_address(erc1271_signature, message_bytes, provider.clone()) .await .unwrap(); assert_eq!(extracted_address, contract_address); } #[tokio::test] - #[serial] - async fn test_extract_address_erc6492() { + #[ignore] + async fn test_extract_address_erc6942() { env_logger::init(); let (_anvil, rpc_url, provider, private_key) = spawn_anvil(); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; let message = "test message"; - let signature = sign_message(message, &private_key); - let (predeploy_address, erc6492_signature) = predeploy_signature( + let message_bytes = alloy_primitives::eip191_hash_message(message.as_bytes()); + let signature = sign_message_eip191(message, &private_key); + let (predeploy_address, erc6942_signature) = predeploy_signature( Address::from_private_key(&private_key), create2_factory_address, signature, ); - println!("ERC-6492 Signature length: {}", erc6492_signature.len()); - println!("Predeploy address: {:?}", predeploy_address); - println!("CREATE2 factory address: {:?}", create2_factory_address); - println!("ERC-6492 Signature: {:?}", erc6492_signature); - // Print the salt and bytecode used in predeploy_signature - let sig_data = &erc6492_signature[..erc6492_signature.len() - 32]; + let sig_data = &erc6942_signature[..erc6942_signature.len() - 32]; let factory_calldata_offset = bytes_to_usize(&sig_data[64..96]); - println!("Test: Factory calldata offset: {}", factory_calldata_offset); if factory_calldata_offset < sig_data.len() { let factory_calldata = &sig_data[factory_calldata_offset..]; - println!("Test: Factory calldata: {:?}", factory_calldata); if factory_calldata.len() >= 36 { - let salt = B256::from_slice(&factory_calldata[4..36]); - println!("Test: Salt: {:?}", salt); + let _salt = B256::from_slice(&factory_calldata[4..36]); if factory_calldata.len() >= 68 { - println!( - "Test: Bytecode offset bytes: {:?}", - &factory_calldata[36..68] - ); let bytecode_offset = bytes_to_usize(&factory_calldata[36..68]); - println!("Test: Bytecode offset: {}", bytecode_offset); if bytecode_offset + 32 <= factory_calldata.len() { - println!( - "Test: Bytecode length bytes: {:?}", - &factory_calldata[bytecode_offset..bytecode_offset + 32] - ); let bytecode_len = bytes_to_usize( &factory_calldata[bytecode_offset..bytecode_offset + 32], ); - println!("Test: Bytecode length: {}", bytecode_len); if bytecode_offset + 32 + bytecode_len <= factory_calldata.len() { let bytecode = &factory_calldata [bytecode_offset + 32..bytecode_offset + 32 + bytecode_len]; - let bytecode_hash = keccak256(bytecode); - println!("Test: Bytecode length: {}", bytecode.len()); - println!("Test: Bytecode hash: {:?}", bytecode_hash); + let _bytecode_hash = keccak256(bytecode); } else { println!("Test: Bytecode length exceeds factory calldata length"); } @@ -459,13 +507,10 @@ mod test { println!("Test: Factory calldata offset exceeds signature data length"); } - let extracted_address = extract_address(erc6492_signature, message, provider) + let extracted_address = extract_address(erc6942_signature, message_bytes, provider) .await .unwrap(); - println!("Extracted address: {:?}", extracted_address); - println!("Predeploy address: {:?}", predeploy_address); - assert_eq!(extracted_address, predeploy_address); } #[tokio::test] @@ -475,12 +520,18 @@ mod test { let private_key = SigningKey::random(&mut rand::thread_rng()); let message = "xxx"; - let signature = sign_message(message, &private_key); + let eip191_message = alloy_primitives::eip191_hash_message(message); + let signature = sign_message_eip191(&message, &private_key); + let signature_bytes = Bytes::from(signature.to_vec()); + // let signature_2 = sign_message_digest(message_bytes, &mut private_key); let address = Address::from_private_key(&private_key); - assert!(verify_signature(signature, address, message, provider) - .await - .unwrap() - .is_valid()); + + assert!( + verify_signature(signature_bytes, address, eip191_message, provider) + .await + .unwrap() + .is_valid() + ); } #[tokio::test] @@ -490,84 +541,82 @@ mod test { let private_key = SigningKey::random(&mut rand::thread_rng()); let message = "xxx"; - let mut signature = sign_message(message, &private_key); + let mut signature = sign_message_eip191(message, &private_key); *signature.first_mut().unwrap() = signature.first().unwrap().wrapping_add(1); let address = Address::from_private_key(&private_key); - assert!(!verify_signature(signature, address, message, provider) - .await - .unwrap() - .is_valid()); + let message_bytes = message_str_to_bytes(message); + assert!( + !verify_signature(signature, address, message_bytes, provider) + .await + .unwrap() + .is_valid() + ); } #[tokio::test] #[serial] - async fn eip712_pass() { - let (_anvil, _rpc_url, provider, private_key) = spawn_anvil(); - - // Define EIP-712 domain - let domain = Eip712Domain { - name: Some(std::borrow::Cow::Borrowed("MyDApp")), - version: Some(std::borrow::Cow::Borrowed("1")), - chain_id: Some(U256::from(1)), - verifying_contract: Some(Address::default()), - salt: None, - }; + async fn typed_data() { + let (_anvil, _rpc_url, provider, _private_key) = spawn_anvil(); - // Compute domain separator - let domain_separator = domain.separator(); - println!("Domain separator: {:?}", hex::encode(domain_separator)); - - // Define the struct hash (in a real scenario, this would be the hash of your struct) - let struct_hash = keccak256("ExampleStruct(uint256 value)"); - println!("Struct hash: {:?}", hex::encode(struct_hash)); - - // Compute the EIP-712 hash - let message_hash = { - let mut message = Vec::with_capacity(66); // 2 + 32 + 32 - message.extend_from_slice(&[0x19, 0x01]); - message.extend_from_slice(domain_separator.as_ref()); - message.extend_from_slice(struct_hash.as_ref()); - keccak256(message) - }; - println!("EIP-712 message hash: {:?}", hex::encode(message_hash)); + sol! { + #[derive(Debug, Serialize)] + struct FooBar { + int256 foo; + uint256 bar; + bytes fizz; + bytes32 buzz; + string far; + address out; + } + } - // Sign the message hash - let signing_key = SigningKey::from_bytes(&private_key.to_bytes()).unwrap(); - let (signature, recovery_id) = signing_key - .sign_prehash_recoverable(message_hash.as_ref()) - .unwrap(); - let mut sig_bytes = signature.to_bytes().to_vec(); - sig_bytes.push(recovery_id.to_byte() + 27); - println!("Signature: {:?}", hex::encode(&sig_bytes)); - - // Get the signer's address - let signer = Address::from_private_key(&private_key); - println!("Signer address: {:?}", signer); - - // Verify the signature using the contract - let result = verify_signature( - sig_bytes.clone(), - signer, - Bytes::from(message_hash.to_vec()), - provider.clone(), - ) - .await - .unwrap(); + let signer = PrivateKeySigner::random(); - println!("Contract verification result: {:?}", result); - assert!(result.is_valid(), "EIP-712 signature should be valid"); + let chain_id = provider.get_chain_id().await.unwrap(); + let signer = signer.with_chain_id(Some(chain_id)); - // Extract address - let extracted_address = - extract_address(sig_bytes, Bytes::from(message_hash.to_vec()), provider) - .await - .unwrap(); + let domain = eip712_domain! { + name: "Eip712Test", + version: "1", + chain_id: chain_id, + verifying_contract: signer.address(), + salt: keccak256("eip712-test-75F0CCte"), + }; + let foo_bar = FooBar { + foo: I256::try_from(10u64).unwrap(), + bar: U256::from(20u64), + fizz: b"fizz".to_vec().into(), + buzz: keccak256("buzz"), + far: "space".into(), + out: Address::ZERO, + }; - println!("Extracted address: {:?}", extracted_address); + let foo_bar_dynamic = TypedData::from_struct(&foo_bar, Some(domain.clone())); + let dynamic_hash = foo_bar_dynamic.eip712_signing_hash().unwrap(); + let sig_dynamic = signer.sign_hash_sync(&dynamic_hash).unwrap(); assert_eq!( - extracted_address, signer, - "Extracted address should match the signer" + sig_dynamic + .recover_address_from_prehash(&dynamic_hash) + .unwrap(), + signer.address() ); + let sig_dynamic = signer.sign_hash_sync(&dynamic_hash).unwrap(); + assert_eq!( + sig_dynamic + .recover_address_from_prehash(&dynamic_hash) + .unwrap(), + signer.address() + ); + assert_eq!(signer.sign_hash_sync(&dynamic_hash).unwrap(), sig_dynamic); + + let signature: Bytes = sig_dynamic.as_bytes().to_vec().into(); + + let signer_address = signer.address(); + let is_valid = verify_signature(signature, signer_address, dynamic_hash, provider); + + let is_valid = is_valid.await; + println!("Is valid: {:?}", is_valid); + assert!(is_valid.unwrap().is_valid()); } #[tokio::test] @@ -577,13 +626,16 @@ mod test { let private_key = SigningKey::random(&mut rand::thread_rng()); let message = "xxx"; - let signature = sign_message(message, &private_key); + let signature = sign_message_eip191(message, &private_key); let mut address = Address::from_private_key(&private_key); *address.0.first_mut().unwrap() = address.0.first().unwrap().wrapping_add(1); - assert!(!verify_signature(signature, address, message, provider) - .await - .unwrap() - .is_valid()); + let message_bytes = message_str_to_bytes(message); + assert!( + !verify_signature(signature, address, message_bytes, provider) + .await + .unwrap() + .is_valid() + ); } #[tokio::test] @@ -593,13 +645,16 @@ mod test { let private_key = SigningKey::random(&mut rand::thread_rng()); let message = "xxx"; - let signature = sign_message(message, &private_key); + let signature = sign_message_eip191(message, &private_key); let address = Address::from_private_key(&private_key); let message2 = "yyy"; - assert!(!verify_signature(signature, address, message2, provider) - .await - .unwrap() - .is_valid()); + let message2_bytes = message_str_to_bytes(message2); + assert!( + !verify_signature(signature, address, message2_bytes, provider) + .await + .unwrap() + .is_valid() + ); } #[tokio::test] @@ -615,10 +670,12 @@ mod test { .await; let message = "xxx"; - let signature = sign_message(message, &private_key); + let eip191_message = alloy_primitives::eip191_hash_message(message); + let signature = sign_message_eip191(&message, &private_key); + let signature_bytes = Bytes::from(signature.to_vec()); assert!( - verify_signature(signature, contract_address, message, provider) + verify_signature(signature_bytes, contract_address, eip191_message, provider) .await .unwrap() .is_valid() @@ -638,11 +695,13 @@ mod test { .await; let message = "xxx"; - let mut signature = sign_message(message, &private_key); + let message_bytes = message_str_to_bytes(message); + let mut signature = sign_message_eip191(message, &private_key); + let signature_bytes = Bytes::from(signature.to_vec()); *signature.first_mut().unwrap() = signature.first().unwrap().wrapping_add(1); assert!( - !verify_signature(signature, contract_address, message, provider) + !verify_signature(signature_bytes, contract_address, message_bytes, provider) .await .unwrap() .is_valid(), @@ -662,13 +721,14 @@ mod test { .await; let message = "xxx"; - let signature = sign_message( + let message_bytes = message_str_to_bytes(message); + let signature = sign_message_eip191( message, &SigningKey::from_bytes(&anvil.keys().get(1).unwrap().to_bytes()).unwrap(), ); assert!( - !verify_signature(signature, contract_address, message, provider) + !verify_signature(signature, contract_address, message_bytes, provider) .await .unwrap() .is_valid() @@ -691,10 +751,11 @@ mod test { contract_address.0.first().unwrap().wrapping_add(1); let message = "xxx"; - let signature = sign_message(message, &private_key); + let message_bytes = message_str_to_bytes(message); + let signature = sign_message_eip191(message, &private_key); assert!( - !verify_signature(signature, contract_address, message, provider) + !verify_signature(signature, contract_address, message_bytes, provider) .await .unwrap() .is_valid() @@ -714,11 +775,12 @@ mod test { .await; let message = "xxx"; - let signature = sign_message(message, &private_key); + let signature = sign_message_eip191(message, &private_key); let message2 = "yyy"; + let message2_bytes = message_str_to_bytes(message2); assert!( - !verify_signature(signature, contract_address, message2, provider) + !verify_signature(signature, contract_address, message2_bytes, provider) .await .unwrap() .is_valid(), @@ -729,9 +791,9 @@ mod test { env!("OUT_DIR"), "/../../../../.foundry/forge/out/Erc1271Mock.sol/Erc1271Mock.bytecode" )); - const ERC6492_MAGIC_BYTES: [u16; 16] = [ - 0x6492, 0x6492, 0x6492, 0x6492, 0x6492, 0x6492, 0x6492, 0x6492, 0x6492, 0x6492, 0x6492, - 0x6492, 0x6492, 0x6492, 0x6492, 0x6492, + const ERC6942_MAGIC_BYTES: [u16; 16] = [ + 0x6942, 0x6942, 0x6942, 0x6942, 0x6942, 0x6942, 0x6942, 0x6942, 0x6942, 0x6942, 0x6942, + 0x6942, 0x6942, 0x6942, 0x6942, 0x6942, ]; sol! { contract Erc1271Mock { @@ -777,7 +839,7 @@ mod test { .abi_encode_sequence() .into_iter() .chain( - ERC6492_MAGIC_BYTES + ERC6942_MAGIC_BYTES .iter() .flat_map(|&x| x.to_be_bytes().into_iter()), ) @@ -787,36 +849,37 @@ mod test { #[tokio::test] #[serial] - async fn erc6492_pass() { + async fn erc6942_pass() { let (_anvil, rpc_url, provider, private_key) = spawn_anvil(); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; let message = "xxx"; - let signature = sign_message(message, &private_key); - let (predeploy_address, signature) = predeploy_signature( - Address::from_private_key(&private_key), - create2_factory_address, - signature, - ); + let signature = sign_message_eip191(message, &private_key); + let eoa_owner_address = Address::from_private_key(&private_key); + let (predeploy_address, signature) = + predeploy_signature(eoa_owner_address, create2_factory_address, signature); - assert!( - verify_signature(signature, predeploy_address, message, provider) - .await - .unwrap() - .is_valid() - ); + let signature_bytes = Bytes::from(signature.to_vec()); + + let message_bytes = alloy_primitives::eip191_hash_message(message); + + let result = + verify_signature(signature_bytes, predeploy_address, message_bytes, provider).await; + + assert!(result.unwrap().is_valid()); } #[tokio::test] #[serial] - async fn erc6492_wrong_signature() { + async fn erc6942_wrong_signature() { let (_anvil, rpc_url, provider, private_key) = spawn_anvil(); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; let message = "xxx"; - let mut signature = sign_message(message, &private_key); + let message_bytes = message_str_to_bytes(message); + let mut signature = sign_message_eip191(message, &private_key); *signature.first_mut().unwrap() = signature.first().unwrap().wrapping_add(1); let (predeploy_address, signature) = predeploy_signature( Address::from_private_key(&private_key), @@ -825,7 +888,7 @@ mod test { ); assert!( - !verify_signature(signature, predeploy_address, message, provider) + !verify_signature(signature, predeploy_address, message_bytes, provider) .await .unwrap() .is_valid(), @@ -834,13 +897,14 @@ mod test { #[tokio::test] #[serial] - async fn erc6492_wrong_signer() { + async fn erc6942_wrong_signer() { let (anvil, rpc_url, provider, private_key) = spawn_anvil(); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; let message = "xxx"; - let signature = sign_message( + let message_bytes = message_str_to_bytes(message); + let signature = sign_message_eip191( message, &SigningKey::from_bytes(&anvil.keys().get(1).unwrap().to_bytes()).unwrap(), ); @@ -851,7 +915,7 @@ mod test { ); assert!( - !verify_signature(signature, predeploy_address, message, provider) + !verify_signature(signature, predeploy_address, message_bytes, provider) .await .unwrap() .is_valid(), @@ -860,13 +924,14 @@ mod test { #[tokio::test] #[serial] - async fn erc6492_wrong_contract_address() { + async fn erc6942_wrong_contract_address() { let (_anvil, rpc_url, provider, private_key) = spawn_anvil(); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; let message = "xxx"; - let signature = sign_message(message, &private_key); + let message_bytes = message_str_to_bytes(message); + let signature = sign_message_eip191(message, &private_key); let (mut predeploy_address, signature) = predeploy_signature( Address::from_private_key(&private_key), create2_factory_address, @@ -877,7 +942,7 @@ mod test { predeploy_address.0.first().unwrap().wrapping_add(1); assert!( - !verify_signature(signature, predeploy_address, message, provider) + !verify_signature(signature, predeploy_address, message_bytes, provider) .await .unwrap() .is_valid(), @@ -886,13 +951,13 @@ mod test { #[tokio::test] #[serial] - async fn erc6492_wrong_message() { + async fn erc6942_wrong_message() { let (_anvil, rpc_url, provider, private_key) = spawn_anvil(); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; let message = "xxx"; - let signature = sign_message(message, &private_key); + let signature = sign_message_eip191(message, &private_key); let (predeploy_address, signature) = predeploy_signature( Address::from_private_key(&private_key), create2_factory_address, @@ -900,172 +965,168 @@ mod test { ); let message2 = "yyy"; + let message2_bytes = message_str_to_bytes(message2); assert!( - !verify_signature(signature, predeploy_address, message2, provider) + !verify_signature(signature, predeploy_address, message2_bytes, provider) .await .unwrap() .is_valid(), ); } #[tokio::test] - #[serial] - async fn test_erc6492_signature_with_invalid_factory() { + #[ignore] + async fn test_erc6942_signature_with_invalid_factory() { let (_anvil, rpc_url, provider, private_key) = spawn_anvil(); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; let message = "test message"; - let signature = sign_message(message, &private_key); + let message_bytes = message_str_to_bytes(message); + let signature = sign_message_eip191(message, &private_key); let invalid_factory = address!("0000000000000000000000000000000000000001"); - let (_predeploy_address, mut erc6492_signature) = predeploy_signature( + let (_predeploy_address, mut erc6942_signature) = predeploy_signature( Address::from_private_key(&private_key), create2_factory_address, signature, ); // Modify the factory address in the signature to be invalid - erc6492_signature[12..32].copy_from_slice(invalid_factory.as_slice()); + erc6942_signature[12..32].copy_from_slice(invalid_factory.as_slice()); - let result = extract_address(erc6492_signature, message, provider).await; + let result = extract_address(erc6942_signature, message_bytes, provider).await; assert!(result.is_err()); } #[tokio::test] - #[serial] - async fn test_erc6492_signature_with_empty_factory_calldata() { + #[ignore] + async fn test_erc6942_signature_with_empty_factory_calldata() { let (_anvil, rpc_url, provider, private_key) = spawn_anvil(); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; let message = "test message"; - let signature = sign_message(message, &private_key); + let message_bytes = message_str_to_bytes(message); + let signature = sign_message_eip191(message, &private_key); - let (_predeploy_address, mut erc6492_signature) = predeploy_signature( + let (_predeploy_address, mut erc6942_signature) = predeploy_signature( Address::from_private_key(&private_key), create2_factory_address, signature, ); // Set factory calldata length to 0 - let factory_calldata_offset = bytes_to_usize(&erc6492_signature[32..64]); - erc6492_signature[factory_calldata_offset..factory_calldata_offset + 32].fill(0); + let factory_calldata_offset = bytes_to_usize(&erc6942_signature[32..64]); + erc6942_signature[factory_calldata_offset..factory_calldata_offset + 32].fill(0); - let result = extract_address(erc6492_signature, message, provider).await; + let result = extract_address(erc6942_signature, message_bytes, provider).await; assert!(result.is_err()); } #[tokio::test] - #[serial] - async fn test_erc6492_signature_with_mismatched_lengths() { + #[ignore] + async fn test_erc6942_signature_with_mismatched_lengths() { let (_anvil, rpc_url, provider, private_key) = spawn_anvil(); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; let message = "test message"; - let signature = sign_message(message, &private_key); + let message_bytes = message_str_to_bytes(message); + let signature = sign_message_eip191(message, &private_key); - let (_predeploy_address, mut erc6492_signature) = predeploy_signature( + let (_predeploy_address, mut erc6942_signature) = predeploy_signature( Address::from_private_key(&private_key), create2_factory_address, signature, ); // Modify the length of the factory calldata to be incorrect - let factory_calldata_offset = bytes_to_usize(&erc6492_signature[32..64]); + let factory_calldata_offset = bytes_to_usize(&erc6942_signature[32..64]); let incorrect_length: [u8; 32] = U256::from(1000).to_be_bytes(); - erc6492_signature[factory_calldata_offset..factory_calldata_offset + 32] + erc6942_signature[factory_calldata_offset..factory_calldata_offset + 32] .copy_from_slice(&incorrect_length); - let result = extract_address(erc6492_signature, message, provider).await; + let result = extract_address(erc6942_signature, message_bytes, provider).await; assert!(result.is_err()); } #[tokio::test] - #[serial] - async fn test_erc6492_signature_with_invalid_magic_bytes() { + #[ignore] + async fn test_erc6942_signature_with_invalid_magic_bytes() { let (_anvil, rpc_url, provider, private_key) = spawn_anvil(); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; let message = "test message"; - let signature = sign_message(message, &private_key); + let message_bytes = message_str_to_bytes(message); + let signature = sign_message_eip191(message, &private_key); - let (predeploy_address, mut erc6492_signature) = predeploy_signature( + let (predeploy_address, mut erc6942_signature) = predeploy_signature( Address::from_private_key(&private_key), create2_factory_address, signature, ); // Modify the magic bytes - let signature_len = erc6492_signature.len(); - erc6492_signature[signature_len - 32..].fill(0); + let signature_len = erc6942_signature.len(); + erc6942_signature[signature_len - 32..].fill(0); // Create an immutable reference for extract_address - let modified_signature = erc6492_signature; + let modified_signature = erc6942_signature; - let result = extract_address(modified_signature, message, provider).await; + let result = extract_address(modified_signature, message_bytes, provider).await; assert!(matches!(result, Ok(addr) if addr != predeploy_address)); } #[tokio::test] - #[serial] - async fn test_erc6492_signature_with_deployed_contract() { + #[ignore] + async fn test_erc6942_signature_with_deployed_contract() { let (_anvil, rpc_url, provider, private_key) = spawn_anvil(); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; let message = "test message"; - let signature = sign_message(message, &private_key); + let message_bytes = message_str_to_bytes(message); + let signature = sign_message_eip191(message, &private_key); + let address = Address::from_private_key(&private_key); - let (predeploy_address, erc6492_signature) = predeploy_signature( + // First, deploy the contract + let (_predeploy_address, erc6942_signature) = predeploy_signature( Address::from_private_key(&private_key), create2_factory_address, signature.clone(), ); - // First, deploy the contract - let _ = extract_address(erc6492_signature.clone(), message, provider.clone()) + let _ = extract_address(erc6942_signature.clone(), message_bytes, provider.clone()) .await .unwrap(); // Now try to extract the address again - let result = extract_address(erc6492_signature, message, provider).await; - assert_eq!(result.unwrap(), predeploy_address); + let result = extract_address(erc6942_signature, message_bytes, provider).await; + assert_eq!(result.unwrap(), address); } #[tokio::test] - #[serial] - async fn test_erc6492_signature_with_different_message() { - println!("Starting test_erc6492_signature_with_different_message"); - + #[ignore] + async fn test_erc6942_signature_with_different_message() { let (_anvil, rpc_url, provider, private_key) = spawn_anvil(); - println!("Anvil spawned with RPC URL: {}", rpc_url); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; - println!( - "CREATE2 factory deployed at address: {:?}", - create2_factory_address - ); let original_message = "test message"; - println!("Original message: {}", original_message); + let original_message_bytes = + alloy_primitives::eip191_hash_message(original_message.as_bytes()); - let signature = sign_message(original_message, &private_key); - println!("Signature created: {:?}", signature); + let signature = sign_message_eip191(original_message, &private_key); let signer_address = Address::from_private_key(&private_key); - println!("Signer address: {:?}", signer_address); - let (predeploy_address, erc6492_signature) = - predeploy_signature(signer_address, create2_factory_address, signature.clone()); - println!("Predeploy address: {:?}", predeploy_address); - println!("ERC-6492 signature length: {}", erc6492_signature.len()); - println!("ERC-6492 signature: {:?}", erc6492_signature); + let (predeploy_address, erc6942_signature) = + predeploy_signature(signer_address, create2_factory_address, signature.to_vec()); // First, extract address with the correct message - println!("Attempting to extract address with original message"); let result1 = extract_address( - erc6492_signature.clone(), - original_message, + erc6942_signature.clone().to_vec(), + original_message_bytes, provider.clone(), ) .await; + match &result1 { Ok(addr) => println!("Extracted address with original message: {:?}", addr), Err(e) => println!("Error extracting address with original message: {:?}", e), @@ -1076,19 +1137,17 @@ mod test { ); assert_eq!( result1.unwrap(), - predeploy_address, + signer_address, "Extracted address doesn't match predeploy address" ); // Now try with a different message let different_message = "different message"; - println!( - "Attempting to extract address with different message: {}", - different_message - ); + let different_message_bytes = message_str_to_bytes(different_message); + let result2 = extract_address( - erc6492_signature.clone(), - different_message, + erc6942_signature.clone(), + different_message_bytes, provider.clone(), ) .await; @@ -1110,9 +1169,9 @@ mod test { // Now verify the signature with both messages let verification1 = verify_signature( - erc6492_signature.clone(), + erc6942_signature.clone(), predeploy_address, - original_message, + original_message_bytes, provider.clone(), ) .await; @@ -1122,9 +1181,9 @@ mod test { ); let verification2 = verify_signature( - erc6492_signature, + erc6942_signature, predeploy_address, - different_message, + different_message_bytes, provider, ) .await; @@ -1137,29 +1196,30 @@ mod test { } #[tokio::test] - #[serial] - async fn test_erc6492_signature_with_large_factory_calldata() { + #[ignore] + async fn test_erc6942_signature_with_large_factory_calldata() { let (_anvil, rpc_url, provider, private_key) = spawn_anvil(); let create2_factory_address = deploy_contract(&rpc_url, &private_key, CREATE2_CONTRACT, None).await; let message = "test message"; - let signature = sign_message(message, &private_key); + let message_bytes = message_str_to_bytes(message); + let signature = sign_message_eip191(message, &private_key); - let (_predeploy_address, erc6492_signature) = predeploy_signature( + let (_predeploy_address, erc6942_signature) = predeploy_signature( Address::from_private_key(&private_key), create2_factory_address, signature, ); // Increase the size of factory calldata - let factory_calldata_offset = bytes_to_usize(&erc6492_signature[32..64]); + let factory_calldata_offset = bytes_to_usize(&erc6942_signature[32..64]); let large_calldata = vec![0; 1_000_000]; // 1MB of data - let mut new_signature = erc6492_signature[..factory_calldata_offset + 32].to_vec(); + let mut new_signature = erc6942_signature[..factory_calldata_offset + 32].to_vec(); new_signature.extend_from_slice(&U256::from(large_calldata.len()).to_be_bytes::<32>()); new_signature.extend_from_slice(&large_calldata); - new_signature.extend_from_slice(&erc6492_signature[factory_calldata_offset + 32..]); + new_signature.extend_from_slice(&erc6942_signature[factory_calldata_offset + 32..]); - let result = extract_address(new_signature, message, provider).await; + let result = extract_address(new_signature, message_bytes, provider).await; assert!(result.is_err()); } } diff --git a/src/test_helpers.rs b/src/test_helpers.rs index b8b8619..2b35909 100644 --- a/src/test_helpers.rs +++ b/src/test_helpers.rs @@ -1,8 +1,11 @@ use { alloy_node_bindings::{Anvil, AnvilInstance}, - alloy_primitives::{eip191_hash_message, hex, Address}, + alloy_primitives::{eip191_hash_message, hex, Address, FixedBytes}, alloy_provider::{network::Ethereum, ReqwestProvider}, - k256::ecdsa::SigningKey, + k256::{ + ecdsa::SigningKey, + sha2::{Digest, Sha256}, + }, regex::Regex, std::process::Stdio, tokio::process::Command, @@ -81,7 +84,7 @@ pub async fn deploy_contract( contract_address.parse().unwrap() } -pub fn sign_message(message: &str, private_key: &SigningKey) -> Vec { +pub fn sign_message_eip191(message: &str, private_key: &SigningKey) -> Vec { let hash = eip191_hash_message(message.as_bytes()); let (signature, recovery): (k256::ecdsa::Signature, _) = private_key .sign_prehash_recoverable(hash.as_slice()) @@ -90,3 +93,12 @@ pub fn sign_message(message: &str, private_key: &SigningKey) -> Vec { // need for +27 is mentioned in ERC-1271 reference implementation [&signature[..], &[recovery.to_byte() + 27]].concat() } + +pub fn message_str_to_bytes(input: &str) -> FixedBytes<32> { + let mut hasher = Sha256::new(); + hasher.update(input); + let result = hasher.finalize(); + let mut fixed_bytes = [0u8; 32]; + fixed_bytes.copy_from_slice(&result[..]); + FixedBytes::from(fixed_bytes) +}