diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 638c4ac6..e76c83db 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,6 @@ jobs: strategy: matrix: package: - - "starknet-ff" - "starknet-curve" - "starknet-crypto-codegen" - "starknet-crypto" diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2000d7a7..2ba9b375 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-11] + os: [ubuntu-latest, macos-12] toolchain: [stable, nightly] steps: @@ -90,10 +90,6 @@ jobs: command: install args: wasm-pack - - name: Run starknet-ff tests - run: | - (cd ./starknet-ff && wasm-pack test --release --node) - - name: Run starknet-crypto tests run: | (cd ./starknet-crypto && wasm-pack test --release --node) @@ -129,22 +125,6 @@ jobs: run: | rustup target add thumbv6m-none-eabi - - name: Build starknet-ff - run: | - cargo build --package starknet-ff \ - --target thumbv6m-none-eabi \ - --no-default-features - - cargo build --package starknet-ff \ - --target thumbv6m-none-eabi \ - --no-default-features \ - --features alloc - - cargo build --package starknet-ff \ - --target thumbv6m-none-eabi \ - --no-default-features \ - --features serde - - name: Build starknet-crypto run: | cargo build --package starknet-crypto \ diff --git a/Cargo.lock b/Cargo.lock index 6ce30066..913a3aa3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -34,70 +43,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" -[[package]] -name = "ark-ff" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" -dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", - "derivative", - "digest", - "itertools", - "num-bigint", - "num-traits", - "paste", - "rustc_version", - "zeroize", -] - -[[package]] -name = "ark-ff-asm" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" -dependencies = [ - "num-bigint", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-serialize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" -dependencies = [ - "ark-std", - "digest", - "num-bigint", -] - -[[package]] -name = "ark-std" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" -dependencies = [ - "num-traits", - "rand", -] - [[package]] name = "arrayvec" version = "0.7.2" @@ -106,13 +51,13 @@ checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.63", ] [[package]] @@ -145,10 +90,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] -name = "base64" -version = "0.13.1" +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide 0.7.4", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" @@ -157,14 +117,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] -name = "bigdecimal" -version = "0.3.0" +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aaf33151a6429fe9211d1b276eafdf70cdff28b071e76c0b0e1503221ea3744" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "num-bigint", - "num-integer", - "num-traits", "serde", ] @@ -174,6 +149,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + [[package]] name = "bitvec" version = "1.0.1" @@ -195,6 +176,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "sha2", + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.12.1" @@ -209,9 +200,9 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -227,9 +218,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" @@ -293,9 +284,9 @@ version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ - "bitflags", + "bitflags 1.3.2", "clap_lex", - "indexmap", + "indexmap 1.9.3", "textwrap", ] @@ -318,6 +309,63 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "coins-bip32" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66c43ff7fd9ff522219058808a259e61423335767b1071d5b346de60d9219657" +dependencies = [ + "bs58", + "coins-core", + "digest", + "hmac", + "k256", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3aeeec621f4daec552e9d28befd58020a78cfc364827d06a753e8bc13c6c4b" +dependencies = [ + "base64 0.21.0", + "bech32", + "bs58", + "const-hex", + "digest", + "generic-array", + "ripemd", + "serde", + "sha2", + "sha3", + "thiserror", +] + +[[package]] +name = "coins-ledger" +version = "0.11.1" +source = "git+https://github.com/xJonathanLEI/coins?rev=0e3be5db0b18b683433de6b666556b99c726e785#0e3be5db0b18b683433de6b666556b99c726e785" +dependencies = [ + "async-trait", + "byteorder", + "cfg-if", + "const-hex", + "getrandom", + "hidapi-rusb", + "js-sys", + "log", + "nix", + "once_cell", + "thiserror", + "tokio", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -328,6 +376,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "const-hex" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -399,6 +466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7" dependencies = [ "generic-array", + "rand_core", "subtle", "zeroize", ] @@ -446,7 +514,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.15", + "syn 2.0.63", ] [[package]] @@ -463,14 +531,14 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.63", ] [[package]] name = "darling" -version = "0.14.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -478,57 +546,100 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.14.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 1.0.109", + "syn 2.0.63", ] [[package]] name = "darling_macro" -version = "0.14.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 1.0.109", + "syn 2.0.63", ] [[package]] -name = "derivative" -version = "2.2.0" +name = "der" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", ] [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "either" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "encoding_rs" version = "0.8.32" @@ -538,6 +649,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "eth-keystore" version = "0.5.0" @@ -587,6 +704,16 @@ dependencies = [ "uint", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "fixed-hash" version = "0.8.0" @@ -606,7 +733,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.6.2", ] [[package]] @@ -677,6 +804,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -692,6 +820,23 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + [[package]] name = "h2" version = "0.3.18" @@ -704,7 +849,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -723,6 +868,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -753,6 +904,18 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hidapi-rusb" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efdc2ec354929a6e8f3c6b6923a4d97427ec2f764cfee8cd4bfe890946cdf08b" +dependencies = [ + "cc", + "libc", + "pkg-config", + "rusb", +] + [[package]] name = "hmac" version = "0.12.1" @@ -813,7 +976,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -918,7 +1081,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", "serde", ] @@ -954,22 +1128,58 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + [[package]] name = "keccak" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] +[[package]] +name = "lambdaworks-crypto" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb5d4f22241504f7c7b8d2c3a7d7835d7c07117f10bff2a7d96a9ef6ef217c3" +dependencies = [ + "lambdaworks-math", + "serde", + "sha2", + "sha3", +] + +[[package]] +name = "lambdaworks-math" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "358e172628e713b80a530a59654154bfc45783a6ed70ea284839800cebdf8f97" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -978,9 +1188,27 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.142" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libusb1-sys" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +checksum = "da050ade7ac4ff1ba5379af847a10a10a8e284181e060105bf8d86960ce9ce0f" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] [[package]] name = "link-cplusplus" @@ -1013,6 +1241,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -1028,29 +1265,56 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + [[package]] name = "mio" -version = "0.8.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "log", "wasi", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset", + "pin-utils", ] [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.45" @@ -1063,11 +1327,12 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1080,11 +1345,20 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" -version = "1.17.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" @@ -1144,15 +1418,9 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.45.0", ] -[[package]] -name = "paste" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" - [[package]] name = "pbkdf2" version = "0.11.0" @@ -1170,9 +1438,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1180,6 +1448,28 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1235,18 +1525,34 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bitflags 2.5.0", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.4", + "unarray", +] + [[package]] name = "quote" -version = "1.0.26" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1287,13 +1593,22 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + [[package]] name = "redox_syscall" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1302,7 +1617,7 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" dependencies = [ - "regex-syntax", + "regex-syntax 0.7.1", ] [[package]] @@ -1311,6 +1626,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + [[package]] name = "reqwest" version = "0.11.16" @@ -1375,6 +1696,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest", +] + [[package]] name = "rlp" version = "0.5.2" @@ -1386,19 +1716,26 @@ dependencies = [ ] [[package]] -name = "rustc-hex" -version = "2.1.0" +name = "rusb" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +checksum = "ab9f9ff05b63a786553a4c02943b74b34a988448671001e9a27e2f0565cc05a4" +dependencies = [ + "libc", + "libusb1-sys", +] [[package]] -name = "rustc_version" -version = "0.4.0" +name = "rustc-demangle" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" [[package]] name = "rustls" @@ -1485,30 +1822,44 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "semver" -version = "1.0.17" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.160" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.63", ] [[package]] @@ -1547,15 +1898,17 @@ dependencies = [ [[package]] name = "serde_with" -version = "2.3.2" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331bb8c3bf9b92457ab7abecf07078c13f7d270ba490103e84e8b014490cd0b0" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" dependencies = [ - "base64 0.13.1", + "base64 0.22.1", "chrono", "hex", - "indexmap", + "indexmap 1.9.3", + "indexmap 2.2.6", "serde", + "serde_derive", "serde_json", "serde_with_macros", "time", @@ -1563,21 +1916,21 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "2.3.2" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859011bddcc11f289f07f467cc1fe01c7a941daa4d8f6c40d4d1c92eb6d9319c" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ "darling", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.63", ] [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -1586,9 +1939,9 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c2bb1a323307527314a36bfb73f24febb08ce2b8a554bf4ffd6f51ad15198c" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ "digest", "keccak", @@ -1603,6 +1956,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "slab" version = "0.4.8" @@ -1628,22 +1991,41 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "starknet" -version = "0.10.0" +version = "0.11.0" dependencies = [ "serde_json", "starknet-accounts", "starknet-contract", "starknet-core", "starknet-crypto", - "starknet-ff", "starknet-macros", "starknet-providers", "starknet-signers", @@ -1653,7 +2035,7 @@ dependencies = [ [[package]] name = "starknet-accounts" -version = "0.9.0" +version = "0.10.0" dependencies = [ "async-trait", "auto_impl", @@ -1670,7 +2052,7 @@ dependencies = [ [[package]] name = "starknet-contract" -version = "0.9.0" +version = "0.10.0" dependencies = [ "rand", "serde", @@ -1687,9 +2069,10 @@ dependencies = [ [[package]] name = "starknet-core" -version = "0.10.0" +version = "0.11.1" dependencies = [ "base64 0.21.0", + "bincode", "criterion", "crypto-bigint", "flate2", @@ -1702,13 +2085,13 @@ dependencies = [ "sha3", "starknet-core", "starknet-crypto", - "starknet-ff", + "starknet-types-core", "wasm-bindgen-test", ] [[package]] name = "starknet-crypto" -version = "0.6.2" +version = "0.7.1" dependencies = [ "criterion", "crypto-bigint", @@ -1724,25 +2107,25 @@ dependencies = [ "sha2", "starknet-crypto-codegen", "starknet-curve", - "starknet-ff", + "starknet-types-core", "wasm-bindgen-test", "zeroize", ] [[package]] name = "starknet-crypto-codegen" -version = "0.3.3" +version = "0.4.0" dependencies = [ "starknet-curve", - "starknet-ff", - "syn 2.0.15", + "starknet-types-core", + "syn 2.0.63", ] [[package]] name = "starknet-curve" -version = "0.4.2" +version = "0.5.0" dependencies = [ - "starknet-ff", + "starknet-types-core", ] [[package]] @@ -1755,36 +2138,23 @@ dependencies = [ "starknet-crypto", ] -[[package]] -name = "starknet-ff" -version = "0.3.7" -dependencies = [ - "ark-ff", - "bigdecimal", - "crypto-bigint", - "getrandom", - "hex", - "num-bigint", - "serde", - "wasm-bindgen-test", -] - [[package]] name = "starknet-macros" -version = "0.1.7" +version = "0.2.0" dependencies = [ "starknet-core", - "syn 2.0.15", + "syn 2.0.63", ] [[package]] name = "starknet-providers" -version = "0.10.0" +version = "0.11.0" dependencies = [ "async-trait", "auto_impl", "ethereum-types", "flate2", + "getrandom", "log", "reqwest", "serde", @@ -1799,26 +2169,43 @@ dependencies = [ [[package]] name = "starknet-signers" -version = "0.8.0" +version = "0.9.0" dependencies = [ "async-trait", "auto_impl", + "coins-bip32", + "coins-ledger", "crypto-bigint", "eth-keystore", + "getrandom", "rand", + "semver", "starknet-core", "starknet-crypto", "thiserror", "wasm-bindgen-test", ] +[[package]] +name = "starknet-types-core" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe29a53d28ff630e4c7827788f14b28f9386d27cb9d05186a5f2e73218c34677" +dependencies = [ + "lambdaworks-crypto", + "lambdaworks-math", + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + [[package]] name = "starknet-wasm" version = "0.1.0" dependencies = [ "console_error_panic_hook", "starknet-crypto", - "starknet-ff", "wasm-bindgen", ] @@ -1830,9 +2217,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" @@ -1853,9 +2240,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" dependencies = [ "proc-macro2", "quote", @@ -1885,31 +2272,34 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.63", ] [[package]] name = "time" -version = "0.3.20" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ + "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -1917,16 +2307,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.8" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -1966,11 +2357,11 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.27.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -1978,20 +2369,20 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.7", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.0.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.63", ] [[package]] @@ -2031,7 +2422,7 @@ version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" dependencies = [ - "indexmap", + "indexmap 1.9.3", "toml_datetime", "winnow", ] @@ -2050,9 +2441,21 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.63", +] + [[package]] name = "tracing-core" version = "0.1.30" @@ -2086,6 +2489,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -2140,6 +2549,12 @@ dependencies = [ "serde", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -2174,9 +2589,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2184,24 +2599,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.63", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -2211,9 +2626,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2221,22 +2636,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.63", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-bindgen-test" @@ -2340,6 +2755,24 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -2370,6 +2803,22 @@ dependencies = [ "windows_x86_64_msvc 0.48.0", ] +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -2382,6 +2831,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -2394,6 +2849,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -2406,6 +2867,18 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -2418,6 +2891,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -2430,6 +2909,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -2442,6 +2927,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -2454,6 +2945,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + [[package]] name = "winnow" version = "0.4.1" @@ -2483,20 +2980,6 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index 7d01e5f2..cb1a68f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet" -version = "0.10.0" +version = "0.11.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -22,7 +22,6 @@ members = [ "starknet-crypto", "starknet-signers", "starknet-accounts", - "starknet-ff", "starknet-macros", "starknet-curve", "starknet-crypto-codegen", @@ -34,24 +33,99 @@ members = [ all-features = true [dependencies] -starknet-ff = { version = "0.3.7", path = "./starknet-ff", default-features = false } -starknet-crypto = { version = "0.6.2", path = "./starknet-crypto" } -starknet-core = { version = "0.10.0", path = "./starknet-core", default-features = false } -starknet-providers = { version = "0.10.0", path = "./starknet-providers" } -starknet-contract = { version = "0.9.0", path = "./starknet-contract" } -starknet-signers = { version = "0.8.0", path = "./starknet-signers" } -starknet-accounts = { version = "0.9.0", path = "./starknet-accounts" } -starknet-macros = { version = "0.1.7", path = "./starknet-macros" } +starknet-crypto = { version = "0.7.1", path = "./starknet-crypto" } +starknet-core = { version = "0.11.1", path = "./starknet-core", default-features = false } +starknet-providers = { version = "0.11.0", path = "./starknet-providers" } +starknet-contract = { version = "0.10.0", path = "./starknet-contract" } +starknet-signers = { version = "0.9.0", path = "./starknet-signers" } +starknet-accounts = { version = "0.10.0", path = "./starknet-accounts" } +starknet-macros = { version = "0.2.0", path = "./starknet-macros" } [dev-dependencies] serde_json = "1.0.74" +starknet-signers = { version = "0.9.0", path = "./starknet-signers", features = ["ledger"] } tokio = { version = "1.15.0", features = ["full"] } url = "2.2.2" [features] -default = ["bigdecimal"] -bigdecimal = ["starknet-ff/bigdecimal"] +default = [] +ledger = ["starknet-signers/ledger"] no_unknown_fields = [ "starknet-core/no_unknown_fields", "starknet-providers/no_unknown_fields", ] + +[workspace.lints] +rust.missing_debug_implementations = "warn" +rust.missing_docs = "allow" +rust.unreachable_pub = "allow" +rust.unused_must_use = "deny" +rust.rust_2018_idioms = { level = "deny", priority = -1 } +rustdoc.all = "warn" + +[workspace.lints.clippy] +# These are some of clippy's nursery (i.e., experimental) lints that we like. +# By default, nursery lints are allowed. Some of the lints below have made good +# suggestions which we fixed. The others didn't have any findings, so we can +# assume they don't have that many false positives. Let's enable them to +# prevent future problems. +branches_sharing_code = "warn" +clear_with_drain = "warn" +derive_partial_eq_without_eq = "warn" +empty_line_after_outer_attr = "warn" +equatable_if_let = "warn" +imprecise_flops = "warn" +iter_on_empty_collections = "warn" +iter_with_drain = "warn" +large_stack_frames = "warn" +manual_clamp = "warn" +mutex_integer = "warn" +needless_pass_by_ref_mut = "warn" +nonstandard_macro_braces = "warn" +or_fun_call = "warn" +path_buf_push_overwrite = "warn" +read_zero_byte_vec = "warn" +redundant_clone = "warn" +suboptimal_flops = "warn" +suspicious_operation_groupings = "warn" +trailing_empty_array = "warn" +trait_duplication_in_bounds = "warn" +transmute_undefined_repr = "warn" +trivial_regex = "warn" +tuple_array_conversions = "warn" +uninhabited_references = "warn" +unused_peekable = "warn" +unused_rounding = "warn" +useless_let_if_seq = "warn" +use_self = "warn" +missing_const_for_fn = "warn" +empty_line_after_doc_comments = "warn" +iter_on_single_items = "warn" +match_same_arms = "warn" +doc_markdown = "warn" +unnecessary_struct_initialization = "warn" +string_lit_as_bytes = "warn" +explicit_into_iter_loop = "warn" +explicit_iter_loop = "warn" +type_repetition_in_bounds = "allow" +manual_string_new = "warn" +naive_bytecount = "warn" +needless_bitwise_bool = "warn" +zero_sized_map_values = "warn" +single_char_pattern = "warn" +needless_continue = "warn" + +# These are nursery lints which have findings. Allow them for now. Some are not +# quite mature enough for use in our codebase and some we don't really want. +# Explicitly listing should make it easier to fix in the future. +as_ptr_cast_mut = "allow" +cognitive_complexity = "allow" +collection_is_never_read = "allow" +debug_assert_with_mut_call = "allow" +fallible_impl_from = "allow" +future_not_send = "allow" +needless_collect = "allow" +non_send_fields_in_send_ty = "allow" +redundant_pub_crate = "allow" +significant_drop_in_scrutinee = "allow" +significant_drop_tightening = "allow" diff --git a/README.md b/README.md index 2a837c5b..ba8e58a1 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ To use the crate from [crates.io](https://crates.io/crates/starknet), add the fo ```toml [dependencies] -starknet = "0.9.0" +starknet = "0.11.0" ``` Note that the [crates.io version](https://crates.io/crates/starknet) might be outdated. You may want to use the library directly from GitHub for all the latest features and fixes: @@ -35,8 +35,9 @@ starknet = { git = "https://github.com/xJonathanLEI/starknet-rs" } - [x] Sequencer gateway / feeder gateway client - [x] Full node JSON-RPC API client - [x] Smart contract deployment -- [x] Signer for using [IAccount](https://github.com/OpenZeppelin/cairo-contracts/blob/main/src/openzeppelin/account/IAccount.cairo) account contracts +- [x] Signer for using [IAccount](https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/src/openzeppelin/account/IAccount.cairo) account contracts - [ ] Strongly-typed smart contract binding code generation from ABI +- [x] Ledger hardware wallet support ## Crates @@ -49,7 +50,6 @@ This workspace contains the following crates: - `starknet-crypto`: **Low-level** cryptography utilities for Starknet - `starknet-signers`: Starknet signer implementations - `starknet-accounts`: Types for handling Starknet account abstraction -- `starknet-ff`: Starknet field element type - `starknet-curve`: Starknet curve operations - `starknet-macros`: Useful macros for using the `starknet` crates @@ -96,9 +96,15 @@ Examples can be found in the [examples folder](./examples): 8. [Deploy an Argent X account to a pre-funded address](./examples/deploy_argent_account.rs) -9. [Parsing a JSON-RPC request on the server side](./examples/parse_jsonrpc_request.rs) +9. [Inspect public key with Ledger](./examples/ledger_public_key.rs) -10. [Inspecting a erased provider-specific error type](./examples/downcast_provider_error.rs) +10. [Deploy an OpenZeppelin account with Ledger](./examples/deploy_account_with_ledger.rs) + +11. [Transfer ERC20 tokens with Ledger](./examples/transfer_with_ledger.rs) + +12. [Parsing a JSON-RPC request on the server side](./examples/parse_jsonrpc_request.rs) + +13. [Inspecting a erased provider-specific error type](./examples/downcast_provider_error.rs) ## License diff --git a/examples/declare_cairo0_contract.rs b/examples/declare_cairo0_contract.rs index 1d5248f6..1bf94b0d 100644 --- a/examples/declare_cairo0_contract.rs +++ b/examples/declare_cairo0_contract.rs @@ -4,7 +4,7 @@ use starknet::{ accounts::{Account, ExecutionEncoding, SingleOwnerAccount}, core::{ chain_id, - types::{contract::legacy::LegacyContractClass, BlockId, BlockTag, FieldElement}, + types::{contract::legacy::LegacyContractClass, BlockId, BlockTag, Felt}, }, providers::{ jsonrpc::{HttpTransport, JsonRpcClient}, @@ -23,9 +23,9 @@ async fn main() { )); let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be("YOUR_PRIVATE_KEY_IN_HEX_HERE").unwrap(), + Felt::from_hex("YOUR_PRIVATE_KEY_IN_HEX_HERE").unwrap(), )); - let address = FieldElement::from_hex_be("YOUR_ACCOUNT_CONTRACT_ADDRESS_IN_HEX_HERE").unwrap(); + let address = Felt::from_hex("YOUR_ACCOUNT_CONTRACT_ADDRESS_IN_HEX_HERE").unwrap(); let mut account = SingleOwnerAccount::new( provider, @@ -45,5 +45,6 @@ async fn main() { .await .unwrap(); - dbg!(result); + println!("Transaction hash: {:#064x}", result.transaction_hash); + println!("Class hash: {:#064x}", result.class_hash); } diff --git a/examples/declare_cairo1_contract.rs b/examples/declare_cairo1_contract.rs index 92811586..86ab0fdd 100644 --- a/examples/declare_cairo1_contract.rs +++ b/examples/declare_cairo1_contract.rs @@ -4,7 +4,7 @@ use starknet::{ accounts::{Account, ExecutionEncoding, SingleOwnerAccount}, core::{ chain_id, - types::{contract::SierraClass, BlockId, BlockTag, FieldElement}, + types::{contract::SierraClass, BlockId, BlockTag, Felt}, }, providers::{ jsonrpc::{HttpTransport, JsonRpcClient}, @@ -21,17 +21,16 @@ async fn main() { .unwrap(); // Class hash of the compiled CASM class from the `starknet-sierra-compile` command - let compiled_class_hash = - FieldElement::from_hex_be("COMPILED_CASM_CLASS_HASH_IN_HEX_HERE").unwrap(); + let compiled_class_hash = Felt::from_hex("COMPILED_CASM_CLASS_HASH_IN_HEX_HERE").unwrap(); let provider = JsonRpcClient::new(HttpTransport::new( Url::parse("https://starknet-sepolia.public.blastapi.io/rpc/v0_7").unwrap(), )); let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be("YOUR_PRIVATE_KEY_IN_HEX_HERE").unwrap(), + Felt::from_hex("YOUR_PRIVATE_KEY_IN_HEX_HERE").unwrap(), )); - let address = FieldElement::from_hex_be("YOUR_ACCOUNT_CONTRACT_ADDRESS_IN_HEX_HERE").unwrap(); + let address = Felt::from_hex("YOUR_ACCOUNT_CONTRACT_ADDRESS_IN_HEX_HERE").unwrap(); let mut account = SingleOwnerAccount::new( provider, @@ -54,5 +53,6 @@ async fn main() { .await .unwrap(); - dbg!(result); + println!("Transaction hash: {:#064x}", result.transaction_hash); + println!("Class hash: {:#064x}", result.class_hash); } diff --git a/examples/deploy_account_with_ledger.rs b/examples/deploy_account_with_ledger.rs new file mode 100644 index 00000000..ef4ba9ae --- /dev/null +++ b/examples/deploy_account_with_ledger.rs @@ -0,0 +1,60 @@ +use starknet::{ + accounts::AccountFactory, + core::chain_id, + macros::felt, + providers::{ + jsonrpc::{HttpTransport, JsonRpcClient}, + Url, + }, + signers::LedgerSigner, +}; +use starknet_accounts::OpenZeppelinAccountFactory; + +#[tokio::main] +async fn main() { + // OpenZeppelin account contract v0.13.0 compiled with cairo v2.6.3 + let class_hash = felt!("0x00e2eb8f5672af4e6a4e8a8f1b44989685e668489b0a25437733756c5a34a1d6"); + + // Anything you like here as salt + let salt = felt!("12345678"); + + let provider = JsonRpcClient::new(HttpTransport::new( + Url::parse("https://starknet-sepolia.public.blastapi.io/rpc/v0_7").unwrap(), + )); + + let signer = LedgerSigner::new( + "m/2645'/1195502025'/1470455285'/0'/0'/0" + .try_into() + .expect("unable to parse path"), + ) + .await + .expect("failed to initialize Starknet Ledger app"); + + let factory = OpenZeppelinAccountFactory::new(class_hash, chain_id::SEPOLIA, signer, provider) + .await + .unwrap(); + + let deployment = factory.deploy_v1(salt); + + let est_fee = deployment.estimate_fee().await.unwrap(); + + // In an actual application you might want to add a buffer to the amount + println!( + "Fund at least {} wei to {:#064x}", + est_fee.overall_fee, + deployment.address() + ); + println!("Press ENTER after account is funded to continue deployment..."); + std::io::stdin().read_line(&mut String::new()).unwrap(); + + let result = deployment.send().await; + match result { + Ok(tx) => { + println!("Transaction hash: {:#064x}", tx.transaction_hash); + println!("Account: {:#064x}", tx.contract_address); + } + Err(err) => { + eprintln!("Error: {err}"); + } + } +} diff --git a/examples/deploy_argent_account.rs b/examples/deploy_argent_account.rs index c3545103..acd559c7 100644 --- a/examples/deploy_argent_account.rs +++ b/examples/deploy_argent_account.rs @@ -1,6 +1,6 @@ use starknet::{ accounts::{AccountFactory, ArgentAccountFactory}, - core::{chain_id, types::FieldElement}, + core::{chain_id, types::Felt}, macros::felt, providers::{ jsonrpc::{HttpTransport, JsonRpcClient}, @@ -22,18 +22,13 @@ async fn main() { )); let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be("YOUR_PRIVATE_KEY_IN_HEX_HERE").unwrap(), + Felt::from_hex("YOUR_PRIVATE_KEY_IN_HEX_HERE").unwrap(), )); - let factory = ArgentAccountFactory::new( - class_hash, - chain_id::SEPOLIA, - FieldElement::ZERO, - signer, - provider, - ) - .await - .unwrap(); + let factory = + ArgentAccountFactory::new(class_hash, chain_id::SEPOLIA, Felt::ZERO, signer, provider) + .await + .unwrap(); let deployment = factory.deploy_v1(salt); @@ -51,7 +46,8 @@ async fn main() { let result = deployment.send().await; match result { Ok(tx) => { - dbg!(tx); + println!("Transaction hash: {:#064x}", tx.transaction_hash); + println!("Account: {:#064x}", tx.contract_address); } Err(err) => { eprintln!("Error: {err}"); diff --git a/examples/deploy_contract.rs b/examples/deploy_contract.rs index 2219fb6f..049bad5e 100644 --- a/examples/deploy_contract.rs +++ b/examples/deploy_contract.rs @@ -5,7 +5,7 @@ use starknet::{ contract::ContractFactory, core::{ chain_id, - types::{contract::legacy::LegacyContractClass, BlockId, BlockTag, FieldElement}, + types::{contract::legacy::LegacyContractClass, BlockId, BlockTag, Felt}, }, macros::felt, providers::{ @@ -28,9 +28,9 @@ async fn main() { )); let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be("YOUR_PRIVATE_KEY_IN_HEX_HERE").unwrap(), + Felt::from_hex("YOUR_PRIVATE_KEY_IN_HEX_HERE").unwrap(), )); - let address = FieldElement::from_hex_be("YOUR_ACCOUNT_CONTRACT_ADDRESS_IN_HEX_HERE").unwrap(); + let address = Felt::from_hex("YOUR_ACCOUNT_CONTRACT_ADDRESS_IN_HEX_HERE").unwrap(); let mut account = SingleOwnerAccount::new( provider, signer, diff --git a/examples/erc20_balance.rs b/examples/erc20_balance.rs index 96f60288..2e21c42a 100644 --- a/examples/erc20_balance.rs +++ b/examples/erc20_balance.rs @@ -1,5 +1,5 @@ use starknet::{ - core::types::{BlockId, BlockTag, FieldElement, FunctionCall}, + core::types::{BlockId, BlockTag, Felt, FunctionCall}, macros::{felt, selector}, providers::{ jsonrpc::{HttpTransport, JsonRpcClient}, @@ -16,20 +16,20 @@ async fn main() { let tst_token_address = felt!("0x07394cbe418daa16e42b87ba67372d4ab4a5df0b05c6e554d158458ce245bc10"); - let call_result = provider - .call( - FunctionCall { - contract_address: tst_token_address, - entry_point_selector: selector!("balanceOf"), - calldata: vec![FieldElement::from_hex_be( - "YOUR_ACCOUNT_CONTRACT_ADDRESS_IN_HEX_HERE", - ) - .unwrap()], - }, - BlockId::Tag(BlockTag::Latest), - ) - .await - .expect("failed to call contract"); + let call_result = + provider + .call( + FunctionCall { + contract_address: tst_token_address, + entry_point_selector: selector!("balanceOf"), + calldata: vec![ + Felt::from_hex("YOUR_ACCOUNT_CONTRACT_ADDRESS_IN_HEX_HERE").unwrap() + ], + }, + BlockId::Tag(BlockTag::Latest), + ) + .await + .expect("failed to call contract"); dbg!(call_result); } diff --git a/examples/ledger_public_key.rs b/examples/ledger_public_key.rs new file mode 100644 index 00000000..36c5636a --- /dev/null +++ b/examples/ledger_public_key.rs @@ -0,0 +1,18 @@ +use starknet::signers::{LedgerSigner, Signer}; + +#[tokio::main] +async fn main() { + let path = "m/2645'/1195502025'/1470455285'/0'/0'/0"; + + let ledger = LedgerSigner::new(path.try_into().expect("unable to parse path")) + .await + .expect("failed to initialize Starknet Ledger app"); + + let public_key = ledger + .get_public_key() + .await + .expect("failed to get public key"); + + println!("Path: {}", path); + println!("Public key: {:#064x}", public_key.scalar()); +} diff --git a/examples/mint_tokens.rs b/examples/mint_tokens.rs index 71718382..64fc7ada 100644 --- a/examples/mint_tokens.rs +++ b/examples/mint_tokens.rs @@ -2,7 +2,7 @@ use starknet::{ accounts::{Account, Call, ExecutionEncoding, SingleOwnerAccount}, core::{ chain_id, - types::{BlockId, BlockTag, FieldElement}, + types::{BlockId, BlockTag, Felt}, utils::get_selector_from_name, }, providers::{ @@ -19,13 +19,11 @@ async fn main() { )); let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be("YOUR_PRIVATE_KEY_IN_HEX_HERE").unwrap(), + Felt::from_hex("YOUR_PRIVATE_KEY_IN_HEX_HERE").unwrap(), )); - let address = FieldElement::from_hex_be("YOUR_ACCOUNT_CONTRACT_ADDRESS_IN_HEX_HERE").unwrap(); - let tst_token_address = FieldElement::from_hex_be( - "07394cbe418daa16e42b87ba67372d4ab4a5df0b05c6e554d158458ce245bc10", - ) - .unwrap(); + let address = Felt::from_hex("YOUR_ACCOUNT_CONTRACT_ADDRESS_IN_HEX_HERE").unwrap(); + let tst_token_address = + Felt::from_hex("07394cbe418daa16e42b87ba67372d4ab4a5df0b05c6e554d158458ce245bc10").unwrap(); let mut account = SingleOwnerAccount::new( provider, @@ -45,13 +43,13 @@ async fn main() { selector: get_selector_from_name("mint").unwrap(), calldata: vec![ address, - FieldElement::from_dec_str("1000000000000000000000").unwrap(), - FieldElement::ZERO, + Felt::from_dec_str("1000000000000000000000").unwrap(), + Felt::ZERO, ], }]) .send() .await .unwrap(); - dbg!(result); + println!("Transaction hash: {:#064x}", result.transaction_hash); } diff --git a/examples/starknet-cxx/README.md b/examples/starknet-cxx/README.md index fc231bcd..1aa0a763 100644 --- a/examples/starknet-cxx/README.md +++ b/examples/starknet-cxx/README.md @@ -8,7 +8,7 @@ As noted in the [`starknet-crypto` page](../../starknet-crypto/), you're advised ## Note -This wrapper crate expose functions that operate on strings, which is bad and probably hurts performance. It's possible to make the C++ side create `FieldElement` instances and operate on those instead, which is much more idiomatic. That said, this demo wrapper crate seems to already offer decent performance. +This wrapper crate expose functions that operate on strings, which is bad and probably hurts performance. It's possible to make the C++ side create `Felt` instances and operate on those instead, which is much more idiomatic. That said, this demo wrapper crate seems to already offer decent performance. Moreover, this crate does not implement error handling and always just panics on error, which is likely not what you want in production. diff --git a/examples/starknet-cxx/starknet-cxx/src/lib.rs b/examples/starknet-cxx/starknet-cxx/src/lib.rs index a45803e0..f34221b5 100644 --- a/examples/starknet-cxx/starknet-cxx/src/lib.rs +++ b/examples/starknet-cxx/starknet-cxx/src/lib.rs @@ -2,7 +2,7 @@ //! https://github.com/xJonathanLEI/starknet-rs/issues/325 //! //! This wrapper crate expose functions that operate on strings, which is bad and probably hurts -//! performance. It's possible to make the C++ side create `FieldElement` instances and operate on +//! performance. It's possible to make the C++ side create `Felt` instances and operate on //! those instead, which is much more idiomatic. That said, this demo wrapper crate seems to already //! offer decent performance. //! @@ -13,7 +13,7 @@ //! create idiomatic bindings, which is way too much work to maintain as an example, and should be //! a project of its own. -use starknet_core::{crypto::Signature, types::FieldElement}; +use starknet_core::{crypto::Signature, types::Felt}; #[cxx::bridge] mod ffi { @@ -26,16 +26,16 @@ mod ffi { pub fn pedersen_hash(x: &str, y: &str) -> String { // WARNING: no error handling here - let x = FieldElement::from_hex_be(x).unwrap(); - let y = FieldElement::from_hex_be(y).unwrap(); + let x = Felt::from_hex(x).unwrap(); + let y = Felt::from_hex(y).unwrap(); format!("{:#064x}", starknet_core::crypto::pedersen_hash(&x, &y)) } fn ecdsa_sign(private_key: &str, message: &str) -> String { // WARNING: no error handling here - let private_key = FieldElement::from_hex_be(private_key).unwrap(); - let message = FieldElement::from_hex_be(message).unwrap(); + let private_key = Felt::from_hex(private_key).unwrap(); + let message = Felt::from_hex(message).unwrap(); let signature: Signature = starknet_core::crypto::ecdsa_sign(&private_key, &message) // WARNING: no error handling here diff --git a/examples/starknet-wasm/Cargo.toml b/examples/starknet-wasm/Cargo.toml index 4d93155d..2ec65513 100644 --- a/examples/starknet-wasm/Cargo.toml +++ b/examples/starknet-wasm/Cargo.toml @@ -19,7 +19,6 @@ crate-type = ["cdylib", "rlib"] default = ["console_error_panic_hook"] [dependencies] -starknet-ff = { version = "0.3.7", path = "../../starknet-ff" } -starknet-crypto = { version = "0.6.2", path = "../../starknet-crypto" } +starknet-crypto = { version = "0.7.1", path = "../../starknet-crypto" } console_error_panic_hook = { version = "0.1.7", optional = true } wasm-bindgen = "0.2.84" diff --git a/examples/starknet-wasm/src/lib.rs b/examples/starknet-wasm/src/lib.rs index 2d6f0625..a32699fa 100644 --- a/examples/starknet-wasm/src/lib.rs +++ b/examples/starknet-wasm/src/lib.rs @@ -1,6 +1,6 @@ #![allow(clippy::unused_unit)] -use starknet_crypto::FieldElement; +use starknet_crypto::Felt; use wasm_bindgen::prelude::*; #[wasm_bindgen] @@ -8,7 +8,7 @@ pub fn get_public_key(private_key_hex: &str) -> String { #[cfg(feature = "console_error_panic_hook")] console_error_panic_hook::set_once(); - let private_key = FieldElement::from_hex_be(private_key_hex).unwrap(); + let private_key = Felt::from_hex(private_key_hex).unwrap(); let public_key = starknet_crypto::get_public_key(&private_key); format!("{public_key:#064x}") diff --git a/examples/transfer_with_ledger.rs b/examples/transfer_with_ledger.rs new file mode 100644 index 00000000..223da492 --- /dev/null +++ b/examples/transfer_with_ledger.rs @@ -0,0 +1,57 @@ +use starknet::{ + accounts::{Account, Call, ExecutionEncoding, SingleOwnerAccount}, + core::{ + chain_id, + types::{BlockId, BlockTag, Felt}, + utils::get_selector_from_name, + }, + macros::felt, + providers::{ + jsonrpc::{HttpTransport, JsonRpcClient}, + Url, + }, + signers::LedgerSigner, +}; + +#[tokio::main] +async fn main() { + let provider = JsonRpcClient::new(HttpTransport::new( + Url::parse("https://starknet-sepolia.public.blastapi.io/rpc/v0_7").unwrap(), + )); + + let signer = LedgerSigner::new( + "m/2645'/1195502025'/1470455285'/0'/0'/0" + .try_into() + .expect("unable to parse path"), + ) + .await + .expect("failed to initialize Starknet Ledger app"); + let address = Felt::from_hex("YOUR_ACCOUNT_CONTRACT_ADDRESS_IN_HEX_HERE").unwrap(); + let eth_token_address = + Felt::from_hex("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7") + .unwrap(); + + let mut account = SingleOwnerAccount::new( + provider, + signer, + address, + chain_id::SEPOLIA, + ExecutionEncoding::New, + ); + + // `SingleOwnerAccount` defaults to checking nonce and estimating fees against the latest + // block. Optionally change the target block to pending with the following line: + account.set_block_id(BlockId::Tag(BlockTag::Pending)); + + let result = account + .execute_v1(vec![Call { + to: eth_token_address, + selector: get_selector_from_name("transfer").unwrap(), + calldata: vec![felt!("0x1234"), felt!("100"), Felt::ZERO], + }]) + .send() + .await + .unwrap(); + + println!("Transaction hash: {:#064x}", result.transaction_hash); +} diff --git a/scripts/build_bench_wasm.sh b/scripts/build_bench_wasm.sh index 9d7a4da8..d8f72238 100755 --- a/scripts/build_bench_wasm.sh +++ b/scripts/build_bench_wasm.sh @@ -17,7 +17,8 @@ mkdir -p $REPO_ROOT/target/bench-wasm cd $REPO_ROOT/starknet-core benches=( - class_hash + cairo0_class_hash + sierra_class_hash ) for bench in ${benches[@]}; do diff --git a/scripts/run_bench_wasm.sh b/scripts/run_bench_wasm.sh index 47c7a417..a36ae83f 100755 --- a/scripts/run_bench_wasm.sh +++ b/scripts/run_bench_wasm.sh @@ -15,7 +15,8 @@ if [ -z "$RUNTIME" ]; then fi benches=( - class_hash + cairo0_class_hash + sierra_class_hash ecdsa_get_public_key ecdsa_recover ecdsa_sign diff --git a/starknet-accounts/Cargo.toml b/starknet-accounts/Cargo.toml index b7feb539..442a53fe 100644 --- a/starknet-accounts/Cargo.toml +++ b/starknet-accounts/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-accounts" -version = "0.9.0" +version = "0.10.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -14,10 +14,10 @@ keywords = ["ethereum", "starknet", "web3"] exclude = ["test-data/**"] [dependencies] -starknet-core = { version = "0.10.0", path = "../starknet-core" } -starknet-crypto = { version = "0.6.2", path = "../starknet-crypto" } -starknet-providers = { version = "0.10.0", path = "../starknet-providers" } -starknet-signers = { version = "0.8.0", path = "../starknet-signers" } +starknet-core = { version = "0.11.1", path = "../starknet-core" } +starknet-crypto = { version = "0.7.1", path = "../starknet-crypto" } +starknet-providers = { version = "0.11.0", path = "../starknet-providers" } +starknet-signers = { version = "0.9.0", path = "../starknet-signers" } async-trait = "0.1.68" auto_impl = "1.0.1" thiserror = "1.0.40" @@ -27,3 +27,6 @@ serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0.96" tokio = { version = "1.27.0", features = ["full"] } url = "2.3.1" + +[lints] +workspace = true diff --git a/starknet-accounts/src/account/declaration.rs b/starknet-accounts/src/account/declaration.rs index f3535ae2..d8d2de4e 100644 --- a/starknet-accounts/src/account/declaration.rs +++ b/starknet-accounts/src/account/declaration.rs @@ -10,9 +10,9 @@ use starknet_core::{ contract::{legacy::LegacyContractClass, ComputeClassHashError}, BroadcastedDeclareTransaction, BroadcastedDeclareTransactionV1, BroadcastedDeclareTransactionV2, BroadcastedDeclareTransactionV3, BroadcastedTransaction, - DataAvailabilityMode, DeclareTransactionResult, FeeEstimate, FieldElement, - FlattenedSierraClass, ResourceBounds, ResourceBoundsMapping, SimulatedTransaction, - SimulationFlag, + DataAvailabilityMode, DeclareTransactionResult, FeeEstimate, Felt, FlattenedSierraClass, + ResourceBounds, ResourceBoundsMapping, SimulatedTransaction, SimulationFlag, + SimulationFlagForEstimateFee, }, }; use starknet_crypto::PoseidonHasher; @@ -20,41 +20,41 @@ use starknet_providers::Provider; use std::sync::Arc; /// Cairo string for "declare" -const PREFIX_DECLARE: FieldElement = FieldElement::from_mont([ - 17542456862011667323, +const PREFIX_DECLARE: Felt = Felt::from_raw([ + 191557713328401194, 18446744073709551615, 18446744073709551615, - 191557713328401194, + 17542456862011667323, ]); /// 2 ^ 128 + 1 -const QUERY_VERSION_ONE: FieldElement = FieldElement::from_mont([ - 18446744073700081633, - 17407, - 18446744073709551584, +const QUERY_VERSION_ONE: Felt = Felt::from_raw([ 576460752142433776, + 18446744073709551584, + 17407, + 18446744073700081633, ]); /// 2 ^ 128 + 2 -const QUERY_VERSION_TWO: FieldElement = FieldElement::from_mont([ - 18446744073700081601, - 17407, - 18446744073709551584, +const QUERY_VERSION_TWO: Felt = Felt::from_raw([ 576460752142433232, + 18446744073709551584, + 17407, + 18446744073700081601, ]); /// 2 ^ 128 + 3 -const QUERY_VERSION_THREE: FieldElement = FieldElement::from_mont([ - 18446744073700081569, - 17407, - 18446744073709551584, +const QUERY_VERSION_THREE: Felt = Felt::from_raw([ 576460752142432688, + 18446744073709551584, + 17407, + 18446744073700081569, ]); impl<'a, A> DeclarationV2<'a, A> { - pub fn new( + pub const fn new( contract_class: Arc, - compiled_class_hash: FieldElement, + compiled_class_hash: Felt, account: &'a A, ) -> Self { Self { @@ -67,14 +67,14 @@ impl<'a, A> DeclarationV2<'a, A> { } } - pub fn nonce(self, nonce: FieldElement) -> Self { + pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), ..self } } - pub fn max_fee(self, max_fee: FieldElement) -> Self { + pub fn max_fee(self, max_fee: Felt) -> Self { Self { max_fee: Some(max_fee), ..self @@ -88,8 +88,8 @@ impl<'a, A> DeclarationV2<'a, A> { } } - /// Calling this function after manually specifying `nonce` and `max_fee` turns [DeclarationV2] - /// into [PreparedDeclarationV2]. Returns `Err` if either field is `None`. + /// Calling this function after manually specifying `nonce` and `max_fee` turns [`DeclarationV2`] + /// into [`PreparedDeclarationV2`]. Returns `Err` if either field is `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; let max_fee = self.max_fee.ok_or(NotPreparedError)?; @@ -162,11 +162,22 @@ where let max_fee = match self.max_fee { Some(value) => value, None => { + // Obtain the fee estimate let fee_estimate = self.estimate_fee_with_nonce(nonce).await?; - ((((TryInto::::try_into(fee_estimate.overall_fee) - .map_err(|_| AccountError::FeeOutOfRange)?) as f64) - * self.fee_estimate_multiplier) as u64) - .into() + // Convert the overall fee to little-endian bytes + let overall_fee_bytes = fee_estimate.overall_fee.to_bytes_le(); + + // Check if the remaining bytes after the first 8 are all zeros + if overall_fee_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountError::FeeOutOfRange); + } + + // Convert the first 8 bytes to u64 + let overall_fee_u64 = + u64::from_le_bytes(overall_fee_bytes[..8].try_into().unwrap()); + + // Perform necessary operations on overall_fee_u64 and convert to f64 then to u64 + (((overall_fee_u64 as f64) * self.fee_estimate_multiplier) as u64).into() } }; @@ -183,24 +194,32 @@ where async fn estimate_fee_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, ) -> Result> { + let skip_signature = self.account.is_signer_interactive(); + let prepared = PreparedDeclarationV2 { account: self.account, inner: RawDeclarationV2 { contract_class: self.contract_class.clone(), compiled_class_hash: self.compiled_class_hash, nonce, - max_fee: FieldElement::ZERO, + max_fee: Felt::ZERO, }, }; - let declare = prepared.get_declare_request(true).await?; + let declare = prepared.get_declare_request(true, skip_signature).await?; self.account .provider() .estimate_fee_single( BroadcastedTransaction::Declare(BroadcastedDeclareTransaction::V2(declare)), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.account.block_id(), ) .await @@ -209,10 +228,20 @@ where async fn simulate_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.account.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedDeclarationV2 { account: self.account, inner: RawDeclarationV2 { @@ -222,7 +251,7 @@ where max_fee: self.max_fee.unwrap_or_default(), }, }; - let declare = prepared.get_declare_request(true).await?; + let declare = prepared.get_declare_request(true, skip_signature).await?; let mut flags = vec![]; @@ -246,9 +275,9 @@ where } impl<'a, A> DeclarationV3<'a, A> { - pub fn new( + pub const fn new( contract_class: Arc, - compiled_class_hash: FieldElement, + compiled_class_hash: Felt, account: &'a A, ) -> Self { Self { @@ -263,7 +292,7 @@ impl<'a, A> DeclarationV3<'a, A> { } } - pub fn nonce(self, nonce: FieldElement) -> Self { + pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), ..self @@ -299,7 +328,7 @@ impl<'a, A> DeclarationV3<'a, A> { } /// Calling this function after manually specifying `nonce`, `gas` and `gas_price` turns - /// [DeclarationV3] into [PreparedDeclarationV3]. Returns `Err` if any field is `None`. + /// [`DeclarationV3`] into [`PreparedDeclarationV3`]. Returns `Err` if any field is `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; let gas = self.gas.ok_or(NotPreparedError)?; @@ -388,10 +417,15 @@ where .l1_gas_price() .price_in_fri; - let gas_price = (((TryInto::::try_into(block_l1_gas_price) - .map_err(|_| AccountError::FeeOutOfRange)?) - as f64) - * self.gas_price_estimate_multiplier) as u128; + let block_l1_gas_price_bytes = block_l1_gas_price.to_bytes_le(); + if block_l1_gas_price_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountError::FeeOutOfRange); + } + let block_l1_gas_price = + u64::from_le_bytes(block_l1_gas_price_bytes[..8].try_into().unwrap()); + + let gas_price = + ((block_l1_gas_price as f64) * self.gas_price_estimate_multiplier) as u128; (gas, gas_price) } @@ -402,12 +436,21 @@ where let gas = match self.gas { Some(gas) => gas, None => { - (((TryInto::::try_into( - (fee_estimate.overall_fee + fee_estimate.gas_price - FieldElement::ONE) - .floor_div(fee_estimate.gas_price), - ) - .map_err(|_| AccountError::FeeOutOfRange)?) - as f64) + let overall_fee_bytes = fee_estimate.overall_fee.to_bytes_le(); + if overall_fee_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountError::FeeOutOfRange); + } + let overall_fee = + u64::from_le_bytes(overall_fee_bytes[..8].try_into().unwrap()); + + let gas_price_bytes = fee_estimate.gas_price.to_bytes_le(); + if gas_price_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountError::FeeOutOfRange); + } + let gas_price = + u64::from_le_bytes(gas_price_bytes[..8].try_into().unwrap()); + + (((overall_fee + gas_price - 1) / gas_price) as f64 * self.gas_estimate_multiplier) as u64 } }; @@ -415,10 +458,14 @@ where let gas_price = match self.gas_price { Some(gas_price) => gas_price, None => { - (((TryInto::::try_into(fee_estimate.gas_price) - .map_err(|_| AccountError::FeeOutOfRange)?) - as f64) - * self.gas_price_estimate_multiplier) as u128 + let gas_price_bytes = fee_estimate.gas_price.to_bytes_le(); + if gas_price_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountError::FeeOutOfRange); + } + let gas_price = + u64::from_le_bytes(gas_price_bytes[..8].try_into().unwrap()); + + ((gas_price as f64) * self.gas_price_estimate_multiplier) as u128 } }; @@ -440,8 +487,10 @@ where async fn estimate_fee_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, ) -> Result> { + let skip_signature = self.account.is_signer_interactive(); + let prepared = PreparedDeclarationV3 { account: self.account, inner: RawDeclarationV3 { @@ -452,13 +501,19 @@ where gas_price: 0, }, }; - let declare = prepared.get_declare_request(true).await?; + let declare = prepared.get_declare_request(true, skip_signature).await?; self.account .provider() .estimate_fee_single( BroadcastedTransaction::Declare(BroadcastedDeclareTransaction::V3(declare)), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.account.block_id(), ) .await @@ -467,10 +522,20 @@ where async fn simulate_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.account.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedDeclarationV3 { account: self.account, inner: RawDeclarationV3 { @@ -481,7 +546,7 @@ where gas_price: self.gas_price.unwrap_or_default(), }, }; - let declare = prepared.get_declare_request(true).await?; + let declare = prepared.get_declare_request(true, skip_signature).await?; let mut flags = vec![]; @@ -505,7 +570,7 @@ where } impl<'a, A> LegacyDeclaration<'a, A> { - pub fn new(contract_class: Arc, account: &'a A) -> Self { + pub const fn new(contract_class: Arc, account: &'a A) -> Self { Self { account, contract_class, @@ -515,14 +580,14 @@ impl<'a, A> LegacyDeclaration<'a, A> { } } - pub fn nonce(self, nonce: FieldElement) -> Self { + pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), ..self } } - pub fn max_fee(self, max_fee: FieldElement) -> Self { + pub fn max_fee(self, max_fee: Felt) -> Self { Self { max_fee: Some(max_fee), ..self @@ -537,7 +602,7 @@ impl<'a, A> LegacyDeclaration<'a, A> { } /// Calling this function after manually specifying `nonce` and `max_fee` turns - /// [LegacyDeclaration] into [PreparedLegacyDeclaration]. Returns `Err` if either field is + /// [`LegacyDeclaration`] into [`PreparedLegacyDeclaration`]. Returns `Err` if either field is /// `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; @@ -612,11 +677,22 @@ where let max_fee = match self.max_fee { Some(value) => value, None => { + // Obtain the fee estimate let fee_estimate = self.estimate_fee_with_nonce(nonce).await?; - ((((TryInto::::try_into(fee_estimate.overall_fee) - .map_err(|_| AccountError::FeeOutOfRange)?) as f64) - * self.fee_estimate_multiplier) as u64) - .into() + // Convert the overall fee to little-endian bytes + let overall_fee_bytes = fee_estimate.overall_fee.to_bytes_le(); + + // Check if the remaining bytes after the first 8 are all zeros + if overall_fee_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountError::FeeOutOfRange); + } + + // Convert the first 8 bytes to u64 + let overall_fee_u64 = + u64::from_le_bytes(overall_fee_bytes[..8].try_into().unwrap()); + + // Perform necessary operations on overall_fee_u64 and convert to f64 then to u64 + (((overall_fee_u64 as f64) * self.fee_estimate_multiplier) as u64).into() } }; @@ -632,23 +708,31 @@ where async fn estimate_fee_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, ) -> Result> { + let skip_signature = self.account.is_signer_interactive(); + let prepared = PreparedLegacyDeclaration { account: self.account, inner: RawLegacyDeclaration { contract_class: self.contract_class.clone(), nonce, - max_fee: FieldElement::ZERO, + max_fee: Felt::ZERO, }, }; - let declare = prepared.get_declare_request(true).await?; + let declare = prepared.get_declare_request(true, skip_signature).await?; self.account .provider() .estimate_fee_single( BroadcastedTransaction::Declare(BroadcastedDeclareTransaction::V1(declare)), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.account.block_id(), ) .await @@ -657,10 +741,20 @@ where async fn simulate_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.account.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedLegacyDeclaration { account: self.account, inner: RawLegacyDeclaration { @@ -669,7 +763,7 @@ where max_fee: self.max_fee.unwrap_or_default(), }, }; - let declare = prepared.get_declare_request(true).await?; + let declare = prepared.get_declare_request(true, skip_signature).await?; let mut flags = vec![]; @@ -693,21 +787,16 @@ where } impl RawDeclarationV2 { - pub fn transaction_hash( - &self, - chain_id: FieldElement, - address: FieldElement, - query_only: bool, - ) -> FieldElement { + pub fn transaction_hash(&self, chain_id: Felt, address: Felt, query_only: bool) -> Felt { compute_hash_on_elements(&[ PREFIX_DECLARE, if query_only { QUERY_VERSION_TWO } else { - FieldElement::TWO + Felt::TWO }, // version address, - FieldElement::ZERO, // entry_point_selector + Felt::ZERO, // entry_point_selector compute_hash_on_elements(&[self.contract_class.class_hash()]), self.max_fee, chain_id, @@ -720,33 +809,28 @@ impl RawDeclarationV2 { &self.contract_class } - pub fn compiled_class_hash(&self) -> FieldElement { + pub const fn compiled_class_hash(&self) -> Felt { self.compiled_class_hash } - pub fn nonce(&self) -> FieldElement { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn max_fee(&self) -> FieldElement { + pub const fn max_fee(&self) -> Felt { self.max_fee } } impl RawDeclarationV3 { - pub fn transaction_hash( - &self, - chain_id: FieldElement, - address: FieldElement, - query_only: bool, - ) -> FieldElement { + pub fn transaction_hash(&self, chain_id: Felt, address: Felt, query_only: bool) -> Felt { let mut hasher = PoseidonHasher::new(); hasher.update(PREFIX_DECLARE); hasher.update(if query_only { QUERY_VERSION_THREE } else { - FieldElement::THREE + Felt::THREE }); hasher.update(address); @@ -754,7 +838,7 @@ impl RawDeclarationV3 { let mut fee_hasher = PoseidonHasher::new(); // Tip: fee market has not been been activated yet so it's hard-coded to be 0 - fee_hasher.update(FieldElement::ZERO); + fee_hasher.update(Felt::ZERO); let mut resource_buffer = [ 0, 0, b'L', b'1', b'_', b'G', b'A', b'S', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -762,14 +846,14 @@ impl RawDeclarationV3 { ]; resource_buffer[8..(8 + 8)].copy_from_slice(&self.gas.to_be_bytes()); resource_buffer[(8 + 8)..].copy_from_slice(&self.gas_price.to_be_bytes()); - fee_hasher.update(FieldElement::from_bytes_be(&resource_buffer).unwrap()); + fee_hasher.update(Felt::from_bytes_be(&resource_buffer)); // L2 resources are hard-coded to 0 let resource_buffer = [ 0, 0, b'L', b'2', b'_', b'G', b'A', b'S', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; - fee_hasher.update(FieldElement::from_bytes_be(&resource_buffer).unwrap()); + fee_hasher.update(Felt::from_bytes_be(&resource_buffer)); fee_hasher.finalize() }); @@ -781,7 +865,7 @@ impl RawDeclarationV3 { hasher.update(self.nonce); // Hard-coded L1 DA mode for nonce and fee - hasher.update(FieldElement::ZERO); + hasher.update(Felt::ZERO); // Hard-coded empty `account_deployment_data` hasher.update(PoseidonHasher::new().finalize()); @@ -796,19 +880,19 @@ impl RawDeclarationV3 { &self.contract_class } - pub fn compiled_class_hash(&self) -> FieldElement { + pub const fn compiled_class_hash(&self) -> Felt { self.compiled_class_hash } - pub fn nonce(&self) -> FieldElement { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn gas(&self) -> u64 { + pub const fn gas(&self) -> u64 { self.gas } - pub fn gas_price(&self) -> u128 { + pub const fn gas_price(&self) -> u128 { self.gas_price } } @@ -816,19 +900,19 @@ impl RawDeclarationV3 { impl RawLegacyDeclaration { pub fn transaction_hash( &self, - chain_id: FieldElement, - address: FieldElement, + chain_id: Felt, + address: Felt, query_only: bool, - ) -> Result { + ) -> Result { Ok(compute_hash_on_elements(&[ PREFIX_DECLARE, if query_only { QUERY_VERSION_ONE } else { - FieldElement::ONE + Felt::ONE }, // version address, - FieldElement::ZERO, // entry_point_selector + Felt::ZERO, // entry_point_selector compute_hash_on_elements(&[self.contract_class.class_hash()?]), self.max_fee, chain_id, @@ -840,11 +924,11 @@ impl RawLegacyDeclaration { &self.contract_class } - pub fn nonce(&self) -> FieldElement { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn max_fee(&self) -> FieldElement { + pub const fn max_fee(&self) -> Felt { self.max_fee } } @@ -855,7 +939,7 @@ where { /// Locally calculates the hash of the transaction to be sent from this declaration given the /// parameters. - pub fn transaction_hash(&self, query_only: bool) -> FieldElement { + pub fn transaction_hash(&self, query_only: bool) -> Felt { self.inner .transaction_hash(self.account.chain_id(), self.account.address(), query_only) } @@ -866,7 +950,7 @@ where A: ConnectedAccount, { pub async fn send(&self) -> Result> { - let tx_request = self.get_declare_request(false).await?; + let tx_request = self.get_declare_request(false, false).await?; self.account .provider() .add_declare_transaction(BroadcastedDeclareTransaction::V2(tx_request)) @@ -874,19 +958,21 @@ where .map_err(AccountError::Provider) } - pub async fn get_declare_request( + async fn get_declare_request( &self, query_only: bool, + skip_signature: bool, ) -> Result> { - let signature = self - .account - .sign_declaration_v2(&self.inner, query_only) - .await - .map_err(AccountError::Signing)?; - Ok(BroadcastedDeclareTransactionV2 { max_fee: self.inner.max_fee, - signature, + signature: if skip_signature { + vec![] + } else { + self.account + .sign_declaration_v2(&self.inner, query_only) + .await + .map_err(AccountError::Signing)? + }, nonce: self.inner.nonce, contract_class: self.inner.contract_class.clone(), compiled_class_hash: self.inner.compiled_class_hash, @@ -902,7 +988,7 @@ where { /// Locally calculates the hash of the transaction to be sent from this declaration given the /// parameters. - pub fn transaction_hash(&self, query_only: bool) -> FieldElement { + pub fn transaction_hash(&self, query_only: bool) -> Felt { self.inner .transaction_hash(self.account.chain_id(), self.account.address(), query_only) } @@ -913,7 +999,7 @@ where A: ConnectedAccount, { pub async fn send(&self) -> Result> { - let tx_request = self.get_declare_request(false).await?; + let tx_request = self.get_declare_request(false, false).await?; self.account .provider() .add_declare_transaction(BroadcastedDeclareTransaction::V3(tx_request)) @@ -921,20 +1007,22 @@ where .map_err(AccountError::Provider) } - pub async fn get_declare_request( + async fn get_declare_request( &self, query_only: bool, + skip_signature: bool, ) -> Result> { - let signature = self - .account - .sign_declaration_v3(&self.inner, query_only) - .await - .map_err(AccountError::Signing)?; - Ok(BroadcastedDeclareTransactionV3 { sender_address: self.account.address(), compiled_class_hash: self.inner.compiled_class_hash, - signature, + signature: if skip_signature { + vec![] + } else { + self.account + .sign_declaration_v3(&self.inner, query_only) + .await + .map_err(AccountError::Signing)? + }, nonce: self.inner.nonce, contract_class: self.inner.contract_class.clone(), resource_bounds: ResourceBoundsMapping { @@ -968,10 +1056,7 @@ where { /// Locally calculates the hash of the transaction to be sent from this declaration given the /// parameters. - pub fn transaction_hash( - &self, - query_only: bool, - ) -> Result { + pub fn transaction_hash(&self, query_only: bool) -> Result { self.inner .transaction_hash(self.account.chain_id(), self.account.address(), query_only) } @@ -982,7 +1067,7 @@ where A: ConnectedAccount, { pub async fn send(&self) -> Result> { - let tx_request = self.get_declare_request(false).await?; + let tx_request = self.get_declare_request(false, false).await?; self.account .provider() .add_declare_transaction(BroadcastedDeclareTransaction::V1(tx_request)) @@ -990,21 +1075,23 @@ where .map_err(AccountError::Provider) } - pub async fn get_declare_request( + async fn get_declare_request( &self, query_only: bool, + skip_signature: bool, ) -> Result> { - let signature = self - .account - .sign_legacy_declaration(&self.inner, query_only) - .await - .map_err(AccountError::Signing)?; - let compressed_class = self.inner.contract_class.compress().unwrap(); Ok(BroadcastedDeclareTransactionV1 { max_fee: self.inner.max_fee, - signature, + signature: if skip_signature { + vec![] + } else { + self.account + .sign_legacy_declaration(&self.inner, query_only) + .await + .map_err(AccountError::Signing)? + }, nonce: self.inner.nonce, contract_class: Arc::new(compressed_class), sender_address: self.account.address(), diff --git a/starknet-accounts/src/account/execution.rs b/starknet-accounts/src/account/execution.rs index d16ec031..3e529a45 100644 --- a/starknet-accounts/src/account/execution.rs +++ b/starknet-accounts/src/account/execution.rs @@ -9,39 +9,39 @@ use starknet_core::{ types::{ BroadcastedInvokeTransaction, BroadcastedInvokeTransactionV1, BroadcastedInvokeTransactionV3, BroadcastedTransaction, DataAvailabilityMode, FeeEstimate, - FieldElement, InvokeTransactionResult, ResourceBounds, ResourceBoundsMapping, - SimulatedTransaction, SimulationFlag, + Felt, InvokeTransactionResult, ResourceBounds, ResourceBoundsMapping, SimulatedTransaction, + SimulationFlag, SimulationFlagForEstimateFee, }, }; use starknet_crypto::PoseidonHasher; use starknet_providers::Provider; /// Cairo string for "invoke" -const PREFIX_INVOKE: FieldElement = FieldElement::from_mont([ - 18443034532770911073, +const PREFIX_INVOKE: Felt = Felt::from_raw([ + 513398556346534256, 18446744073709551615, 18446744073709551615, - 513398556346534256, + 18443034532770911073, ]); /// 2 ^ 128 + 1 -const QUERY_VERSION_ONE: FieldElement = FieldElement::from_mont([ - 18446744073700081633, - 17407, - 18446744073709551584, +const QUERY_VERSION_ONE: Felt = Felt::from_raw([ 576460752142433776, + 18446744073709551584, + 17407, + 18446744073700081633, ]); /// 2 ^ 128 + 3 -const QUERY_VERSION_THREE: FieldElement = FieldElement::from_mont([ - 18446744073700081569, - 17407, - 18446744073709551584, +const QUERY_VERSION_THREE: Felt = Felt::from_raw([ 576460752142432688, + 18446744073709551584, + 17407, + 18446744073700081569, ]); impl<'a, A> ExecutionV1<'a, A> { - pub fn new(calls: Vec, account: &'a A) -> Self { + pub const fn new(calls: Vec, account: &'a A) -> Self { Self { account, calls, @@ -51,14 +51,14 @@ impl<'a, A> ExecutionV1<'a, A> { } } - pub fn nonce(self, nonce: FieldElement) -> Self { + pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), ..self } } - pub fn max_fee(self, max_fee: FieldElement) -> Self { + pub fn max_fee(self, max_fee: Felt) -> Self { Self { max_fee: Some(max_fee), ..self @@ -72,8 +72,8 @@ impl<'a, A> ExecutionV1<'a, A> { } } - /// Calling this function after manually specifying `nonce` and `max_fee` turns [ExecutionV1] into - /// [PreparedExecutionV1]. Returns `Err` if either field is `None`. + /// Calling this function after manually specifying `nonce` and `max_fee` turns [`ExecutionV1`] into + /// [`PreparedExecutionV1`]. Returns `Err` if either field is `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; let max_fee = self.max_fee.ok_or(NotPreparedError)?; @@ -90,7 +90,7 @@ impl<'a, A> ExecutionV1<'a, A> { } impl<'a, A> ExecutionV3<'a, A> { - pub fn new(calls: Vec, account: &'a A) -> Self { + pub const fn new(calls: Vec, account: &'a A) -> Self { Self { account, calls, @@ -102,7 +102,7 @@ impl<'a, A> ExecutionV3<'a, A> { } } - pub fn nonce(self, nonce: FieldElement) -> Self { + pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), ..self @@ -138,7 +138,7 @@ impl<'a, A> ExecutionV3<'a, A> { } /// Calling this function after manually specifying `nonce`, `gas` and `gas_price` turns - /// [ExecutionV3] into [PreparedExecutionV3]. Returns `Err` if any field is `None`. + /// [`ExecutionV3`] into [`PreparedExecutionV3`]. Returns `Err` if any field is `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; let gas = self.gas.ok_or(NotPreparedError)?; @@ -212,11 +212,22 @@ where let max_fee = match self.max_fee { Some(value) => value, None => { + // Obtain the fee estimate let fee_estimate = self.estimate_fee_with_nonce(nonce).await?; - ((((TryInto::::try_into(fee_estimate.overall_fee) - .map_err(|_| AccountError::FeeOutOfRange)?) as f64) - * self.fee_estimate_multiplier) as u64) - .into() + // Convert the overall fee to little-endian bytes + let overall_fee_bytes = fee_estimate.overall_fee.to_bytes_le(); + + // Check if the remaining bytes after the first 8 are all zeros + if overall_fee_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountError::FeeOutOfRange); + } + + // Convert the first 8 bytes to u64 + let overall_fee_u64 = + u64::from_le_bytes(overall_fee_bytes[..8].try_into().unwrap()); + + // Perform necessary operations on overall_fee_u64 and convert to f64 then to u64 + (((overall_fee_u64 as f64) * self.fee_estimate_multiplier) as u64).into() } }; @@ -232,18 +243,20 @@ where async fn estimate_fee_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, ) -> Result> { + let skip_signature = self.account.is_signer_interactive(); + let prepared = PreparedExecutionV1 { account: self.account, inner: RawExecutionV1 { calls: self.calls.clone(), nonce, - max_fee: FieldElement::ZERO, + max_fee: Felt::ZERO, }, }; let invoke = prepared - .get_invoke_request(true) + .get_invoke_request(true, skip_signature) .await .map_err(AccountError::Signing)?; @@ -251,7 +264,13 @@ where .provider() .estimate_fee_single( BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(invoke)), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.account.block_id(), ) .await @@ -260,10 +279,20 @@ where async fn simulate_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.account.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedExecutionV1 { account: self.account, inner: RawExecutionV1 { @@ -273,7 +302,7 @@ where }, }; let invoke = prepared - .get_invoke_request(true) + .get_invoke_request(true, skip_signature) .await .map_err(AccountError::Signing)?; @@ -368,10 +397,15 @@ where .l1_gas_price() .price_in_fri; - let gas_price = (((TryInto::::try_into(block_l1_gas_price) - .map_err(|_| AccountError::FeeOutOfRange)?) - as f64) - * self.gas_price_estimate_multiplier) as u128; + let block_l1_gas_price_bytes = block_l1_gas_price.to_bytes_le(); + if block_l1_gas_price_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountError::FeeOutOfRange); + } + let block_l1_gas_price = + u64::from_le_bytes(block_l1_gas_price_bytes[..8].try_into().unwrap()); + + let gas_price = + ((block_l1_gas_price as f64) * self.gas_price_estimate_multiplier) as u128; (gas, gas_price) } @@ -382,12 +416,21 @@ where let gas = match self.gas { Some(gas) => gas, None => { - (((TryInto::::try_into( - (fee_estimate.overall_fee + fee_estimate.gas_price - FieldElement::ONE) - .floor_div(fee_estimate.gas_price), - ) - .map_err(|_| AccountError::FeeOutOfRange)?) - as f64) + let overall_fee_bytes = fee_estimate.overall_fee.to_bytes_le(); + if overall_fee_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountError::FeeOutOfRange); + } + let overall_fee = + u64::from_le_bytes(overall_fee_bytes[..8].try_into().unwrap()); + + let gas_price_bytes = fee_estimate.gas_price.to_bytes_le(); + if gas_price_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountError::FeeOutOfRange); + } + let gas_price = + u64::from_le_bytes(gas_price_bytes[..8].try_into().unwrap()); + + ((((overall_fee + gas_price - 1) / gas_price) as f64) * self.gas_estimate_multiplier) as u64 } }; @@ -395,10 +438,14 @@ where let gas_price = match self.gas_price { Some(gas_price) => gas_price, None => { - (((TryInto::::try_into(fee_estimate.gas_price) - .map_err(|_| AccountError::FeeOutOfRange)?) - as f64) - * self.gas_price_estimate_multiplier) as u128 + let gas_price_bytes = fee_estimate.gas_price.to_bytes_le(); + if gas_price_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountError::FeeOutOfRange); + } + let gas_price = + u64::from_le_bytes(gas_price_bytes[..8].try_into().unwrap()); + + ((gas_price as f64) * self.gas_price_estimate_multiplier) as u128 } }; @@ -419,8 +466,10 @@ where async fn estimate_fee_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, ) -> Result> { + let skip_signature = self.account.is_signer_interactive(); + let prepared = PreparedExecutionV3 { account: self.account, inner: RawExecutionV3 { @@ -431,7 +480,7 @@ where }, }; let invoke = prepared - .get_invoke_request(true) + .get_invoke_request(true, skip_signature) .await .map_err(AccountError::Signing)?; @@ -439,7 +488,13 @@ where .provider() .estimate_fee_single( BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V3(invoke)), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.account.block_id(), ) .await @@ -448,10 +503,20 @@ where async fn simulate_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.account.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedExecutionV3 { account: self.account, inner: RawExecutionV3 { @@ -462,7 +527,7 @@ where }, }; let invoke = prepared - .get_invoke_request(true) + .get_invoke_request(true, skip_signature) .await .map_err(AccountError::Signing)?; @@ -490,11 +555,11 @@ where impl RawExecutionV1 { pub fn transaction_hash( &self, - chain_id: FieldElement, - address: FieldElement, + chain_id: Felt, + address: Felt, query_only: bool, encoder: E, - ) -> FieldElement + ) -> Felt where E: ExecutionEncoder, { @@ -503,10 +568,10 @@ impl RawExecutionV1 { if query_only { QUERY_VERSION_ONE } else { - FieldElement::ONE + Felt::ONE }, // version address, - FieldElement::ZERO, // entry_point_selector + Felt::ZERO, // entry_point_selector compute_hash_on_elements(&encoder.encode_calls(&self.calls)), self.max_fee, chain_id, @@ -518,11 +583,11 @@ impl RawExecutionV1 { &self.calls } - pub fn nonce(&self) -> FieldElement { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn max_fee(&self) -> FieldElement { + pub const fn max_fee(&self) -> Felt { self.max_fee } } @@ -530,11 +595,11 @@ impl RawExecutionV1 { impl RawExecutionV3 { pub fn transaction_hash( &self, - chain_id: FieldElement, - address: FieldElement, + chain_id: Felt, + address: Felt, query_only: bool, encoder: E, - ) -> FieldElement + ) -> Felt where E: ExecutionEncoder, { @@ -544,7 +609,7 @@ impl RawExecutionV3 { hasher.update(if query_only { QUERY_VERSION_THREE } else { - FieldElement::THREE + Felt::THREE }); hasher.update(address); @@ -552,7 +617,7 @@ impl RawExecutionV3 { let mut fee_hasher = PoseidonHasher::new(); // Tip: fee market has not been been activated yet so it's hard-coded to be 0 - fee_hasher.update(FieldElement::ZERO); + fee_hasher.update(Felt::ZERO); let mut resource_buffer = [ 0, 0, b'L', b'1', b'_', b'G', b'A', b'S', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -560,14 +625,14 @@ impl RawExecutionV3 { ]; resource_buffer[8..(8 + 8)].copy_from_slice(&self.gas.to_be_bytes()); resource_buffer[(8 + 8)..].copy_from_slice(&self.gas_price.to_be_bytes()); - fee_hasher.update(FieldElement::from_bytes_be(&resource_buffer).unwrap()); + fee_hasher.update(Felt::from_bytes_be(&resource_buffer)); // L2 resources are hard-coded to 0 let resource_buffer = [ 0, 0, b'L', b'2', b'_', b'G', b'A', b'S', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; - fee_hasher.update(FieldElement::from_bytes_be(&resource_buffer).unwrap()); + fee_hasher.update(Felt::from_bytes_be(&resource_buffer)); fee_hasher.finalize() }); @@ -579,7 +644,7 @@ impl RawExecutionV3 { hasher.update(self.nonce); // Hard-coded L1 DA mode for nonce and fee - hasher.update(FieldElement::ZERO); + hasher.update(Felt::ZERO); // Hard-coded empty `account_deployment_data` hasher.update(PoseidonHasher::new().finalize()); @@ -602,15 +667,15 @@ impl RawExecutionV3 { &self.calls } - pub fn nonce(&self) -> FieldElement { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn gas(&self) -> u64 { + pub const fn gas(&self) -> u64 { self.gas } - pub fn gas_price(&self) -> u128 { + pub const fn gas_price(&self) -> u128 { self.gas_price } } @@ -621,7 +686,7 @@ where { /// Locally calculates the hash of the transaction to be sent from this execution given the /// parameters. - pub fn transaction_hash(&self, query_only: bool) -> FieldElement { + pub fn transaction_hash(&self, query_only: bool) -> Felt { self.inner.transaction_hash( self.account.chain_id(), self.account.address(), @@ -637,7 +702,7 @@ where { /// Locally calculates the hash of the transaction to be sent from this execution given the /// parameters. - pub fn transaction_hash(&self, query_only: bool) -> FieldElement { + pub fn transaction_hash(&self, query_only: bool) -> Felt { self.inner.transaction_hash( self.account.chain_id(), self.account.address(), @@ -653,7 +718,7 @@ where { pub async fn send(&self) -> Result> { let tx_request = self - .get_invoke_request(false) + .get_invoke_request(false, false) .await .map_err(AccountError::Signing)?; self.account @@ -666,18 +731,20 @@ where // The `simulate` function is temporarily removed until it's supported in [Provider] // TODO: add `simulate` back once transaction simulation in supported - pub async fn get_invoke_request( + async fn get_invoke_request( &self, query_only: bool, + skip_signature: bool, ) -> Result { - let signature = self - .account - .sign_execution_v1(&self.inner, query_only) - .await?; - Ok(BroadcastedInvokeTransactionV1 { max_fee: self.inner.max_fee, - signature, + signature: if skip_signature { + vec![] + } else { + self.account + .sign_execution_v1(&self.inner, query_only) + .await? + }, nonce: self.inner.nonce, sender_address: self.account.address(), calldata: self.account.encode_calls(&self.inner.calls), @@ -692,7 +759,7 @@ where { pub async fn send(&self) -> Result> { let tx_request = self - .get_invoke_request(false) + .get_invoke_request(false, false) .await .map_err(AccountError::Signing)?; self.account @@ -705,19 +772,21 @@ where // The `simulate` function is temporarily removed until it's supported in [Provider] // TODO: add `simulate` back once transaction simulation in supported - pub async fn get_invoke_request( + async fn get_invoke_request( &self, query_only: bool, + skip_signature: bool, ) -> Result { - let signature = self - .account - .sign_execution_v3(&self.inner, query_only) - .await?; - Ok(BroadcastedInvokeTransactionV3 { sender_address: self.account.address(), calldata: self.account.encode_calls(&self.inner.calls), - signature, + signature: if skip_signature { + vec![] + } else { + self.account + .sign_execution_v3(&self.inner, query_only) + .await? + }, nonce: self.inner.nonce, resource_bounds: ResourceBoundsMapping { l1_gas: ResourceBounds { diff --git a/starknet-accounts/src/account/mod.rs b/starknet-accounts/src/account/mod.rs index 615f09ee..5bb2db3e 100644 --- a/starknet-accounts/src/account/mod.rs +++ b/starknet-accounts/src/account/mod.rs @@ -4,7 +4,7 @@ use async_trait::async_trait; use auto_impl::auto_impl; use starknet_core::types::{ contract::{legacy::LegacyContractClass, CompressProgramError, ComputeClassHashError}, - BlockId, BlockTag, FieldElement, FlattenedSierraClass, + BlockId, BlockTag, Felt, FlattenedSierraClass, }; use starknet_providers::{Provider, ProviderError}; use std::{error::Error, sync::Arc}; @@ -21,86 +21,97 @@ mod execution; pub trait Account: ExecutionEncoder + Sized { type SignError: Error + Send + Sync; - fn address(&self) -> FieldElement; + fn address(&self) -> Felt; - fn chain_id(&self) -> FieldElement; + fn chain_id(&self) -> Felt; async fn sign_execution_v1( &self, execution: &RawExecutionV1, query_only: bool, - ) -> Result, Self::SignError>; + ) -> Result, Self::SignError>; async fn sign_execution_v3( &self, execution: &RawExecutionV3, query_only: bool, - ) -> Result, Self::SignError>; + ) -> Result, Self::SignError>; async fn sign_declaration_v2( &self, declaration: &RawDeclarationV2, query_only: bool, - ) -> Result, Self::SignError>; + ) -> Result, Self::SignError>; async fn sign_declaration_v3( &self, declaration: &RawDeclarationV3, query_only: bool, - ) -> Result, Self::SignError>; + ) -> Result, Self::SignError>; async fn sign_legacy_declaration( &self, legacy_declaration: &RawLegacyDeclaration, query_only: bool, - ) -> Result, Self::SignError>; + ) -> Result, Self::SignError>; - fn execute_v1(&self, calls: Vec) -> ExecutionV1 { + /// Whether the underlying signer implementation is interactive, such as a hardware wallet. + /// Implementations should return `true` if the signing operation is very expensive, even if not + /// strictly "interactive" as in requiring human input. + /// + /// This affects how an account makes decision on whether to request a real signature for + /// estimation/simulation purposes. + fn is_signer_interactive(&self) -> bool; + + fn execute_v1(&self, calls: Vec) -> ExecutionV1<'_, Self> { ExecutionV1::new(calls, self) } - fn execute_v3(&self, calls: Vec) -> ExecutionV3 { + fn execute_v3(&self, calls: Vec) -> ExecutionV3<'_, Self> { ExecutionV3::new(calls, self) } #[deprecated = "use version specific variants (`execute_v1` & `execute_v3`) instead"] - fn execute(&self, calls: Vec) -> ExecutionV1 { + fn execute(&self, calls: Vec) -> ExecutionV1<'_, Self> { self.execute_v1(calls) } fn declare_v2( &self, contract_class: Arc, - compiled_class_hash: FieldElement, - ) -> DeclarationV2 { + compiled_class_hash: Felt, + ) -> DeclarationV2<'_, Self> { DeclarationV2::new(contract_class, compiled_class_hash, self) } fn declare_v3( &self, contract_class: Arc, - compiled_class_hash: FieldElement, - ) -> DeclarationV3 { + compiled_class_hash: Felt, + ) -> DeclarationV3<'_, Self> { DeclarationV3::new(contract_class, compiled_class_hash, self) } - #[deprecated = "use version specific variants (`declare_v1` & `declare_v3`) instead"] + #[deprecated = "use version specific variants (`declare_v2` & `declare_v3`) instead"] fn declare( &self, contract_class: Arc, - compiled_class_hash: FieldElement, - ) -> DeclarationV2 { + compiled_class_hash: Felt, + ) -> DeclarationV2<'_, Self> { self.declare_v2(contract_class, compiled_class_hash) } - fn declare_legacy(&self, contract_class: Arc) -> LegacyDeclaration { + fn declare_legacy( + &self, + contract_class: Arc, + ) -> LegacyDeclaration<'_, Self> { LegacyDeclaration::new(contract_class, self) } } #[auto_impl(&, Box, Arc)] pub trait ExecutionEncoder { - fn encode_calls(&self, calls: &[Call]) -> Vec; + fn encode_calls(&self, calls: &[Call]) -> Vec; } /// An [Account] implementation that also comes with a [Provider]. Functionalities that require a @@ -118,7 +129,7 @@ pub trait ConnectedAccount: Account { BlockId::Tag(BlockTag::Latest) } - async fn get_nonce(&self) -> Result { + async fn get_nonce(&self) -> Result { self.provider() .get_nonce(self.block_id(), self.address()) .await @@ -127,7 +138,7 @@ pub trait ConnectedAccount: Account { /// Abstraction over `INVOKE` transactions from accounts for invoking contracts. This struct uses /// v1 `INVOKE` transactions under the hood, and hence pays transaction fees in ETH. To use v3 -/// transactions for STRK fee payment, use [ExecutionV3] instead. +/// transactions for STRK fee payment, use [`ExecutionV3`] instead. /// /// This is an intermediate type allowing users to optionally specify `nonce` and/or `max_fee`. #[must_use] @@ -135,14 +146,14 @@ pub trait ConnectedAccount: Account { pub struct ExecutionV1<'a, A> { account: &'a A, calls: Vec, - nonce: Option, - max_fee: Option, + nonce: Option, + max_fee: Option, fee_estimate_multiplier: f64, } /// Abstraction over `INVOKE` transactions from accounts for invoking contracts. This struct uses /// v3 `INVOKE` transactions under the hood, and hence pays transaction fees in STRK. To use v1 -/// transactions for ETH fee payment, use [ExecutionV1] instead. +/// transactions for ETH fee payment, use [`ExecutionV1`] instead. /// /// This is an intermediate type allowing users to optionally specify `nonce`, `gas`, and/or /// `gas_price`. @@ -151,7 +162,7 @@ pub struct ExecutionV1<'a, A> { pub struct ExecutionV3<'a, A> { account: &'a A, calls: Vec, - nonce: Option, + nonce: Option, gas: Option, gas_price: Option, gas_estimate_multiplier: f64, @@ -160,7 +171,7 @@ pub struct ExecutionV3<'a, A> { /// Abstraction over `DECLARE` transactions from accounts for invoking contracts. This struct uses /// v2 `DECLARE` transactions under the hood, and hence pays transaction fees in ETH. To use v3 -/// transactions for STRK fee payment, use [DeclarationV3] instead. +/// transactions for STRK fee payment, use [`DeclarationV3`] instead. /// /// An intermediate type allowing users to optionally specify `nonce` and/or `max_fee`. #[must_use] @@ -168,15 +179,15 @@ pub struct ExecutionV3<'a, A> { pub struct DeclarationV2<'a, A> { account: &'a A, contract_class: Arc, - compiled_class_hash: FieldElement, - nonce: Option, - max_fee: Option, + compiled_class_hash: Felt, + nonce: Option, + max_fee: Option, fee_estimate_multiplier: f64, } /// Abstraction over `DECLARE` transactions from accounts for invoking contracts. This struct uses /// v3 `DECLARE` transactions under the hood, and hence pays transaction fees in STRK. To use v2 -/// transactions for ETH fee payment, use [DeclarationV2] instead. +/// transactions for ETH fee payment, use [`DeclarationV2`] instead. /// /// This is an intermediate type allowing users to optionally specify `nonce`, `gas`, and/or /// `gas_price`. @@ -185,8 +196,8 @@ pub struct DeclarationV2<'a, A> { pub struct DeclarationV3<'a, A> { account: &'a A, contract_class: Arc, - compiled_class_hash: FieldElement, - nonce: Option, + compiled_class_hash: Felt, + nonce: Option, gas: Option, gas_price: Option, gas_estimate_multiplier: f64, @@ -199,84 +210,84 @@ pub struct DeclarationV3<'a, A> { pub struct LegacyDeclaration<'a, A> { account: &'a A, contract_class: Arc, - nonce: Option, - max_fee: Option, + nonce: Option, + max_fee: Option, fee_estimate_multiplier: f64, } -/// [ExecutionV1] but with `nonce` and `max_fee` already determined. +/// [`ExecutionV1`] but with `nonce` and `max_fee` already determined. #[derive(Debug)] pub struct RawExecutionV1 { calls: Vec, - nonce: FieldElement, - max_fee: FieldElement, + nonce: Felt, + max_fee: Felt, } -/// [ExecutionV3] but with `nonce`, `gas` and `gas_price` already determined. +/// [`ExecutionV3`] but with `nonce`, `gas` and `gas_price` already determined. #[derive(Debug)] pub struct RawExecutionV3 { calls: Vec, - nonce: FieldElement, + nonce: Felt, gas: u64, gas_price: u128, } -/// [DeclarationV2] but with `nonce` and `max_fee` already determined. +/// [`DeclarationV2`] but with `nonce` and `max_fee` already determined. #[derive(Debug)] pub struct RawDeclarationV2 { contract_class: Arc, - compiled_class_hash: FieldElement, - nonce: FieldElement, - max_fee: FieldElement, + compiled_class_hash: Felt, + nonce: Felt, + max_fee: Felt, } -/// [DeclarationV3] but with `nonce`, `gas` and `gas_price` already determined. +/// [`DeclarationV3`] but with `nonce`, `gas` and `gas_price` already determined. #[derive(Debug)] pub struct RawDeclarationV3 { contract_class: Arc, - compiled_class_hash: FieldElement, - nonce: FieldElement, + compiled_class_hash: Felt, + nonce: Felt, gas: u64, gas_price: u128, } -/// [LegacyDeclaration] but with `nonce` and `max_fee` already determined. +/// [`LegacyDeclaration`] but with `nonce` and `max_fee` already determined. #[derive(Debug)] pub struct RawLegacyDeclaration { contract_class: Arc, - nonce: FieldElement, - max_fee: FieldElement, + nonce: Felt, + max_fee: Felt, } -/// [RawExecutionV1] but with an account associated. +/// [`RawExecutionV1`] but with an account associated. #[derive(Debug)] pub struct PreparedExecutionV1<'a, A> { account: &'a A, inner: RawExecutionV1, } -/// [RawExecutionV3] but with an account associated. +/// [`RawExecutionV3`] but with an account associated. #[derive(Debug)] pub struct PreparedExecutionV3<'a, A> { account: &'a A, inner: RawExecutionV3, } -/// [RawDeclarationV2] but with an account associated. +/// [`RawDeclarationV2`] but with an account associated. #[derive(Debug)] pub struct PreparedDeclarationV2<'a, A> { account: &'a A, inner: RawDeclarationV2, } -/// [RawDeclarationV3] but with an account associated. +/// [`RawDeclarationV3`] but with an account associated. #[derive(Debug)] pub struct PreparedDeclarationV3<'a, A> { account: &'a A, inner: RawDeclarationV3, } -/// [RawLegacyDeclaration] but with an account associated. +/// [`RawLegacyDeclaration`] but with an account associated. #[derive(Debug)] pub struct PreparedLegacyDeclaration<'a, A> { account: &'a A, @@ -305,11 +316,11 @@ where { type SignError = A::SignError; - fn address(&self) -> FieldElement { + fn address(&self) -> Felt { (*self).address() } - fn chain_id(&self) -> FieldElement { + fn chain_id(&self) -> Felt { (*self).chain_id() } @@ -317,7 +328,7 @@ where &self, execution: &RawExecutionV1, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { (*self).sign_execution_v1(execution, query_only).await } @@ -325,7 +336,7 @@ where &self, execution: &RawExecutionV3, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { (*self).sign_execution_v3(execution, query_only).await } @@ -333,7 +344,7 @@ where &self, declaration: &RawDeclarationV2, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { (*self).sign_declaration_v2(declaration, query_only).await } @@ -341,7 +352,7 @@ where &self, declaration: &RawDeclarationV3, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { (*self).sign_declaration_v3(declaration, query_only).await } @@ -349,11 +360,15 @@ where &self, legacy_declaration: &RawLegacyDeclaration, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { (*self) .sign_legacy_declaration(legacy_declaration, query_only) .await } + + fn is_signer_interactive(&self) -> bool { + (*self).is_signer_interactive() + } } #[cfg_attr(not(target_arch = "wasm32"), async_trait)] @@ -364,11 +379,11 @@ where { type SignError = A::SignError; - fn address(&self) -> FieldElement { + fn address(&self) -> Felt { self.as_ref().address() } - fn chain_id(&self) -> FieldElement { + fn chain_id(&self) -> Felt { self.as_ref().chain_id() } @@ -376,7 +391,7 @@ where &self, execution: &RawExecutionV1, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { self.as_ref().sign_execution_v1(execution, query_only).await } @@ -384,7 +399,7 @@ where &self, execution: &RawExecutionV3, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { self.as_ref().sign_execution_v3(execution, query_only).await } @@ -392,7 +407,7 @@ where &self, declaration: &RawDeclarationV2, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { self.as_ref() .sign_declaration_v2(declaration, query_only) .await @@ -402,7 +417,7 @@ where &self, declaration: &RawDeclarationV3, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { self.as_ref() .sign_declaration_v3(declaration, query_only) .await @@ -412,11 +427,15 @@ where &self, legacy_declaration: &RawLegacyDeclaration, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { self.as_ref() .sign_legacy_declaration(legacy_declaration, query_only) .await } + + fn is_signer_interactive(&self) -> bool { + self.as_ref().is_signer_interactive() + } } #[cfg_attr(not(target_arch = "wasm32"), async_trait)] @@ -427,11 +446,11 @@ where { type SignError = A::SignError; - fn address(&self) -> FieldElement { + fn address(&self) -> Felt { self.as_ref().address() } - fn chain_id(&self) -> FieldElement { + fn chain_id(&self) -> Felt { self.as_ref().chain_id() } @@ -439,7 +458,7 @@ where &self, execution: &RawExecutionV1, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { self.as_ref().sign_execution_v1(execution, query_only).await } @@ -447,7 +466,7 @@ where &self, execution: &RawExecutionV3, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { self.as_ref().sign_execution_v3(execution, query_only).await } @@ -455,7 +474,7 @@ where &self, declaration: &RawDeclarationV2, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { self.as_ref() .sign_declaration_v2(declaration, query_only) .await @@ -465,7 +484,7 @@ where &self, declaration: &RawDeclarationV3, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { self.as_ref() .sign_declaration_v3(declaration, query_only) .await @@ -475,11 +494,15 @@ where &self, legacy_declaration: &RawLegacyDeclaration, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { self.as_ref() .sign_legacy_declaration(legacy_declaration, query_only) .await } + + fn is_signer_interactive(&self) -> bool { + self.as_ref().is_signer_interactive() + } } #[cfg_attr(not(target_arch = "wasm32"), async_trait)] @@ -498,7 +521,7 @@ where (*self).block_id() } - async fn get_nonce(&self) -> Result { + async fn get_nonce(&self) -> Result { (*self).get_nonce().await } } @@ -519,7 +542,7 @@ where self.as_ref().block_id() } - async fn get_nonce(&self) -> Result { + async fn get_nonce(&self) -> Result { self.as_ref().get_nonce().await } } @@ -540,7 +563,7 @@ where self.as_ref().block_id() } - async fn get_nonce(&self) -> Result { + async fn get_nonce(&self) -> Result { self.as_ref().get_nonce().await } } diff --git a/starknet-accounts/src/call.rs b/starknet-accounts/src/call.rs index 9afd5112..6d86ed53 100644 --- a/starknet-accounts/src/call.rs +++ b/starknet-accounts/src/call.rs @@ -1,8 +1,8 @@ -use starknet_core::types::FieldElement; +use starknet_core::types::Felt; #[derive(Debug, Clone)] pub struct Call { - pub to: FieldElement, - pub selector: FieldElement, - pub calldata: Vec, + pub to: Felt, + pub selector: Felt, + pub calldata: Vec, } diff --git a/starknet-accounts/src/factory/argent.rs b/starknet-accounts/src/factory/argent.rs index 86e1870a..a8cf6482 100644 --- a/starknet-accounts/src/factory/argent.rs +++ b/starknet-accounts/src/factory/argent.rs @@ -4,15 +4,16 @@ use crate::{ }; use async_trait::async_trait; -use starknet_core::types::{BlockId, BlockTag, FieldElement}; +use starknet_core::types::{BlockId, BlockTag, Felt}; use starknet_providers::Provider; use starknet_signers::Signer; +#[derive(Debug)] pub struct ArgentAccountFactory { - class_hash: FieldElement, - chain_id: FieldElement, - owner_public_key: FieldElement, - guardian_public_key: FieldElement, + class_hash: Felt, + chain_id: Felt, + owner_public_key: Felt, + guardian_public_key: Felt, signer: S, provider: P, block_id: BlockId, @@ -23,9 +24,9 @@ where S: Signer, { pub async fn new( - class_hash: FieldElement, - chain_id: FieldElement, - guardian_public_key: FieldElement, + class_hash: Felt, + chain_id: Felt, + guardian_public_key: Felt, signer: S, provider: P, ) -> Result { @@ -57,15 +58,15 @@ where type Provider = P; type SignError = S::SignError; - fn class_hash(&self) -> FieldElement { + fn class_hash(&self) -> Felt { self.class_hash } - fn calldata(&self) -> Vec { + fn calldata(&self) -> Vec { vec![self.owner_public_key, self.guardian_public_key] } - fn chain_id(&self) -> FieldElement { + fn chain_id(&self) -> Felt { self.chain_id } @@ -73,6 +74,10 @@ where &self.provider } + fn is_signer_interactive(&self) -> bool { + self.signer.is_interactive() + } + fn block_id(&self) -> BlockId { self.block_id } @@ -80,9 +85,10 @@ where async fn sign_deployment_v1( &self, deployment: &RawAccountDeploymentV1, - ) -> Result, Self::SignError> { - let tx_hash = - PreparedAccountDeploymentV1::from_raw(deployment.clone(), self).transaction_hash(); + query_only: bool, + ) -> Result, Self::SignError> { + let tx_hash = PreparedAccountDeploymentV1::from_raw(deployment.clone(), self) + .transaction_hash(query_only); let signature = self.signer.sign_hash(&tx_hash).await?; Ok(vec![signature.r, signature.s]) @@ -91,9 +97,10 @@ where async fn sign_deployment_v3( &self, deployment: &RawAccountDeploymentV3, - ) -> Result, Self::SignError> { - let tx_hash = - PreparedAccountDeploymentV3::from_raw(deployment.clone(), self).transaction_hash(); + query_only: bool, + ) -> Result, Self::SignError> { + let tx_hash = PreparedAccountDeploymentV3::from_raw(deployment.clone(), self) + .transaction_hash(query_only); let signature = self.signer.sign_hash(&tx_hash).await?; Ok(vec![signature.r, signature.s]) diff --git a/starknet-accounts/src/factory/mod.rs b/starknet-accounts/src/factory/mod.rs index 33488367..17f3d2a2 100644 --- a/starknet-accounts/src/factory/mod.rs +++ b/starknet-accounts/src/factory/mod.rs @@ -7,8 +7,8 @@ use starknet_core::{ BlockId, BlockTag, BroadcastedDeployAccountTransaction, BroadcastedDeployAccountTransactionV1, BroadcastedDeployAccountTransactionV3, BroadcastedTransaction, DataAvailabilityMode, DeployAccountTransactionResult, FeeEstimate, - FieldElement, ResourceBounds, ResourceBoundsMapping, SimulatedTransaction, SimulationFlag, - StarknetError, + Felt, NonZeroFelt, ResourceBounds, ResourceBoundsMapping, SimulatedTransaction, + SimulationFlag, SimulationFlagForEstimateFee, StarknetError, }, }; use starknet_crypto::PoseidonHasher; @@ -18,28 +18,44 @@ use std::error::Error; pub mod argent; pub mod open_zeppelin; -/// Cairo string for "deploy_account" -const PREFIX_DEPLOY_ACCOUNT: FieldElement = FieldElement::from_mont([ - 3350261884043292318, - 18443211694809419988, - 18446744073709551615, +/// Cairo string for `deploy_account` +const PREFIX_DEPLOY_ACCOUNT: Felt = Felt::from_raw([ 461298303000467581, + 18446744073709551615, + 18443211694809419988, + 3350261884043292318, ]); -/// Cairo string for "STARKNET_CONTRACT_ADDRESS" -const PREFIX_CONTRACT_ADDRESS: FieldElement = FieldElement::from_mont([ - 3829237882463328880, - 17289941567720117366, - 8635008616843941496, +/// 2 ^ 128 + 1 +const QUERY_VERSION_ONE: Felt = Felt::from_raw([ + 576460752142433776, + 18446744073709551584, + 17407, + 18446744073700081633, +]); + +/// 2 ^ 128 + 3 +const QUERY_VERSION_THREE: Felt = Felt::from_raw([ + 576460752142432688, + 18446744073709551584, + 17407, + 18446744073700081569, +]); + +/// Cairo string for `STARKNET_CONTRACT_ADDRESS` +const PREFIX_CONTRACT_ADDRESS: Felt = Felt::from_raw([ 533439743893157637, + 8635008616843941496, + 17289941567720117366, + 3829237882463328880, ]); // 2 ** 251 - 256 -const ADDR_BOUND: FieldElement = FieldElement::from_mont([ - 18446743986131443745, - 160989183, - 18446744073709255680, +const ADDR_BOUND: NonZeroFelt = NonZeroFelt::from_raw([ 576459263475590224, + 18446744073709255680, + 160989183, + 18446743986131443745, ]); /// This trait enables deploying account contracts using the `DeployAccount` transaction type. @@ -49,14 +65,22 @@ pub trait AccountFactory: Sized { type Provider: Provider + Sync; type SignError: Error + Send + Sync; - fn class_hash(&self) -> FieldElement; + fn class_hash(&self) -> Felt; - fn calldata(&self) -> Vec; + fn calldata(&self) -> Vec; - fn chain_id(&self) -> FieldElement; + fn chain_id(&self) -> Felt; fn provider(&self) -> &Self::Provider; + /// Whether the underlying signer implementation is interactive, such as a hardware wallet. + /// Implementations should return `true` if the signing operation is very expensive, even if not + /// strictly "interactive" as in requiring human input. + /// + /// This affects how an account factory makes decision on whether to request a real signature + /// for estimation/simulation purposes. + fn is_signer_interactive(&self) -> bool; + /// Block ID to use when estimating fees. fn block_id(&self) -> BlockId { BlockId::Tag(BlockTag::Latest) @@ -65,47 +89,49 @@ pub trait AccountFactory: Sized { async fn sign_deployment_v1( &self, deployment: &RawAccountDeploymentV1, - ) -> Result, Self::SignError>; + query_only: bool, + ) -> Result, Self::SignError>; async fn sign_deployment_v3( &self, deployment: &RawAccountDeploymentV3, - ) -> Result, Self::SignError>; + query_only: bool, + ) -> Result, Self::SignError>; - fn deploy_v1(&self, salt: FieldElement) -> AccountDeploymentV1 { + fn deploy_v1(&self, salt: Felt) -> AccountDeploymentV1<'_, Self> { AccountDeploymentV1::new(salt, self) } - fn deploy_v3(&self, salt: FieldElement) -> AccountDeploymentV3 { + fn deploy_v3(&self, salt: Felt) -> AccountDeploymentV3<'_, Self> { AccountDeploymentV3::new(salt, self) } #[deprecated = "use version specific variants (`deploy_v1` & `deploy_v3`) instead"] - fn deploy(&self, salt: FieldElement) -> AccountDeploymentV1 { + fn deploy(&self, salt: Felt) -> AccountDeploymentV1<'_, Self> { self.deploy_v1(salt) } } /// Abstraction over `DEPLOY_ACCOUNT` transactions for account contract deployment. This struct uses /// v1 `DEPLOY_ACCOUNT` transactions under the hood, and hence pays transaction fees in ETH. To use -/// v3 transactions for STRK fee payment, use [AccountDeploymentV3] instead. +/// v3 transactions for STRK fee payment, use [`AccountDeploymentV3`] instead. /// /// An intermediate type allowing users to optionally specify `nonce` and/or `max_fee`. #[must_use] #[derive(Debug)] pub struct AccountDeploymentV1<'f, F> { factory: &'f F, - salt: FieldElement, + salt: Felt, // We need to allow setting nonce here as `DeployAccount` transactions may have non-zero nonces /// after failed transactions can be included in blocks. - nonce: Option, - max_fee: Option, + nonce: Option, + max_fee: Option, fee_estimate_multiplier: f64, } /// Abstraction over `DEPLOY_ACCOUNT` transactions for account contract deployment. This struct uses /// v3 `DEPLOY_ACCOUNT` transactions under the hood, and hence pays transaction fees in STRK. To use -/// v1 transactions for ETH fee payment, use [AccountDeploymentV1] instead. +/// v1 transactions for ETH fee payment, use [`AccountDeploymentV1`] instead. /// /// This is an intermediate type allowing users to optionally specify `nonce`, `gas`, and/or /// `gas_price`. @@ -113,41 +139,41 @@ pub struct AccountDeploymentV1<'f, F> { #[derive(Debug)] pub struct AccountDeploymentV3<'f, F> { factory: &'f F, - salt: FieldElement, + salt: Felt, // We need to allow setting nonce here as `DeployAccount` transactions may have non-zero nonces /// after failed transactions can be included in blocks. - nonce: Option, + nonce: Option, gas: Option, gas_price: Option, gas_estimate_multiplier: f64, gas_price_estimate_multiplier: f64, } -/// [AccountDeploymentV1] but with `nonce` and `max_fee` already determined. +/// [`AccountDeploymentV1`] but with `nonce` and `max_fee` already determined. #[derive(Debug, Clone)] pub struct RawAccountDeploymentV1 { - salt: FieldElement, - nonce: FieldElement, - max_fee: FieldElement, + salt: Felt, + nonce: Felt, + max_fee: Felt, } -/// [AccountDeploymentV3] but with `nonce`, `gas` and `gas_price` already determined. +/// [`AccountDeploymentV3`] but with `nonce`, `gas` and `gas_price` already determined. #[derive(Debug, Clone)] pub struct RawAccountDeploymentV3 { - salt: FieldElement, - nonce: FieldElement, + salt: Felt, + nonce: Felt, gas: u64, gas_price: u128, } -/// [RawAccountDeploymentV1] but with a factory associated. +/// [`RawAccountDeploymentV1`] but with a factory associated. #[derive(Debug)] pub struct PreparedAccountDeploymentV1<'f, F> { factory: &'f F, inner: RawAccountDeploymentV1, } -/// [RawAccountDeploymentV3] but with a factory associated. +/// [`RawAccountDeploymentV3`] but with a factory associated. #[derive(Debug)] pub struct PreparedAccountDeploymentV3<'f, F> { factory: &'f F, @@ -165,7 +191,7 @@ pub enum AccountFactoryError { } impl<'f, F> AccountDeploymentV1<'f, F> { - pub fn new(salt: FieldElement, factory: &'f F) -> Self { + pub const fn new(salt: Felt, factory: &'f F) -> Self { Self { factory, salt, @@ -175,21 +201,21 @@ impl<'f, F> AccountDeploymentV1<'f, F> { } } - pub fn nonce(self, nonce: FieldElement) -> Self { + pub const fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), ..self } } - pub fn max_fee(self, max_fee: FieldElement) -> Self { + pub const fn max_fee(self, max_fee: Felt) -> Self { Self { max_fee: Some(max_fee), ..self } } - pub fn fee_estimate_multiplier(self, fee_estimate_multiplier: f64) -> Self { + pub const fn fee_estimate_multiplier(self, fee_estimate_multiplier: f64) -> Self { Self { fee_estimate_multiplier, ..self @@ -197,7 +223,7 @@ impl<'f, F> AccountDeploymentV1<'f, F> { } /// Calling this function after manually specifying `nonce` and `max_fee` turns - /// [AccountDeploymentV1] into [PreparedAccountDeploymentV1]. Returns `Err` if either field is + /// [`AccountDeploymentV1`] into [`PreparedAccountDeploymentV1`]. Returns `Err` if either field is /// `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; @@ -215,7 +241,7 @@ impl<'f, F> AccountDeploymentV1<'f, F> { } impl<'f, F> AccountDeploymentV3<'f, F> { - pub fn new(salt: FieldElement, factory: &'f F) -> Self { + pub const fn new(salt: Felt, factory: &'f F) -> Self { Self { factory, salt, @@ -227,35 +253,35 @@ impl<'f, F> AccountDeploymentV3<'f, F> { } } - pub fn nonce(self, nonce: FieldElement) -> Self { + pub const fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), ..self } } - pub fn gas(self, gas: u64) -> Self { + pub const fn gas(self, gas: u64) -> Self { Self { gas: Some(gas), ..self } } - pub fn gas_price(self, gas_price: u128) -> Self { + pub const fn gas_price(self, gas_price: u128) -> Self { Self { gas_price: Some(gas_price), ..self } } - pub fn gas_estimate_multiplier(self, gas_estimate_multiplier: f64) -> Self { + pub const fn gas_estimate_multiplier(self, gas_estimate_multiplier: f64) -> Self { Self { gas_estimate_multiplier, ..self } } - pub fn gas_price_estimate_multiplier(self, gas_price_estimate_multiplier: f64) -> Self { + pub const fn gas_price_estimate_multiplier(self, gas_price_estimate_multiplier: f64) -> Self { Self { gas_price_estimate_multiplier, ..self @@ -263,7 +289,7 @@ impl<'f, F> AccountDeploymentV3<'f, F> { } /// Calling this function after manually specifying `nonce` and `max_fee` turns - /// [AccountDeploymentV3] into [PreparedAccountDeploymentV3]. Returns `Err` if either field is + /// [`AccountDeploymentV3`] into [`PreparedAccountDeploymentV3`]. Returns `Err` if either field is /// `None`. pub fn prepared(self) -> Result, NotPreparedError> { let nonce = self.nonce.ok_or(NotPreparedError)?; @@ -287,7 +313,7 @@ where F: AccountFactory + Sync, { /// Locally calculates the target deployment address. - pub fn address(&self) -> FieldElement { + pub fn address(&self) -> Felt { calculate_contract_address( self.salt, self.factory.class_hash(), @@ -295,7 +321,7 @@ where ) } - pub async fn fetch_nonce(&self) -> Result { + pub async fn fetch_nonce(&self) -> Result { match self .factory .provider() @@ -303,9 +329,7 @@ where .await { Ok(nonce) => Ok(nonce), - Err(ProviderError::StarknetError(StarknetError::ContractNotFound)) => { - Ok(FieldElement::ZERO) - } + Err(ProviderError::StarknetError(StarknetError::ContractNotFound)) => Ok(Felt::ZERO), Err(err) => Err(err), } } @@ -363,11 +387,23 @@ where let max_fee = match self.max_fee { Some(value) => value, None => { + // TODO: remove this when a proper u64 conversion is implemented for `Felt` + // Obtain the fee estimate let fee_estimate = self.estimate_fee_with_nonce(nonce).await?; - ((((TryInto::::try_into(fee_estimate.overall_fee) - .map_err(|_| AccountFactoryError::FeeOutOfRange)?) as f64) - * self.fee_estimate_multiplier) as u64) - .into() + // Convert the overall fee to little-endian bytes + let overall_fee_bytes = fee_estimate.overall_fee.to_bytes_le(); + + // Check if the remaining bytes after the first 8 are all zeros + if overall_fee_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountFactoryError::FeeOutOfRange); + } + + // Convert the first 8 bytes to u64 + let overall_fee_u64 = + u64::from_le_bytes(overall_fee_bytes[..8].try_into().unwrap()); + + // Perform necessary operations on overall_fee_u64 and convert to f64 then to u64 + (((overall_fee_u64 as f64) * self.fee_estimate_multiplier) as u64).into() } }; @@ -383,18 +419,20 @@ where async fn estimate_fee_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, ) -> Result> { + let skip_signature = self.factory.is_signer_interactive(); + let prepared = PreparedAccountDeploymentV1 { factory: self.factory, inner: RawAccountDeploymentV1 { salt: self.salt, nonce, - max_fee: FieldElement::ZERO, + max_fee: Felt::ZERO, }, }; let deploy = prepared - .get_deploy_request() + .get_deploy_request(true, skip_signature) .await .map_err(AccountFactoryError::Signing)?; @@ -404,7 +442,13 @@ where BroadcastedTransaction::DeployAccount(BroadcastedDeployAccountTransaction::V1( deploy, )), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.factory.block_id(), ) .await @@ -413,10 +457,20 @@ where async fn simulate_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.factory.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedAccountDeploymentV1 { factory: self.factory, inner: RawAccountDeploymentV1 { @@ -426,7 +480,7 @@ where }, }; let deploy = prepared - .get_deploy_request() + .get_deploy_request(true, skip_signature) .await .map_err(AccountFactoryError::Signing)?; @@ -458,7 +512,7 @@ where F: AccountFactory + Sync, { /// Locally calculates the target deployment address. - pub fn address(&self) -> FieldElement { + pub fn address(&self) -> Felt { calculate_contract_address( self.salt, self.factory.class_hash(), @@ -466,7 +520,7 @@ where ) } - pub async fn fetch_nonce(&self) -> Result { + pub async fn fetch_nonce(&self) -> Result { match self .factory .provider() @@ -474,9 +528,7 @@ where .await { Ok(nonce) => Ok(nonce), - Err(ProviderError::StarknetError(StarknetError::ContractNotFound)) => { - Ok(FieldElement::ZERO) - } + Err(ProviderError::StarknetError(StarknetError::ContractNotFound)) => Ok(Felt::ZERO), Err(err) => Err(err), } } @@ -548,10 +600,15 @@ where .l1_gas_price() .price_in_fri; - let gas_price = (((TryInto::::try_into(block_l1_gas_price) - .map_err(|_| AccountFactoryError::FeeOutOfRange)?) - as f64) - * self.gas_price_estimate_multiplier) as u128; + let block_l1_gas_price_bytes = block_l1_gas_price.to_bytes_le(); + if block_l1_gas_price_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountFactoryError::FeeOutOfRange); + } + let block_l1_gas_price = + u64::from_le_bytes(block_l1_gas_price_bytes[..8].try_into().unwrap()); + + let gas_price = + ((block_l1_gas_price as f64) * self.gas_price_estimate_multiplier) as u128; (gas, gas_price) } @@ -562,12 +619,21 @@ where let gas = match self.gas { Some(gas) => gas, None => { - (((TryInto::::try_into( - (fee_estimate.overall_fee + fee_estimate.gas_price - FieldElement::ONE) - .floor_div(fee_estimate.gas_price), - ) - .map_err(|_| AccountFactoryError::FeeOutOfRange)?) - as f64) + let overall_fee_bytes = fee_estimate.overall_fee.to_bytes_le(); + if overall_fee_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountFactoryError::FeeOutOfRange); + } + let overall_fee = + u64::from_le_bytes(overall_fee_bytes[..8].try_into().unwrap()); + + let gas_price_bytes = fee_estimate.gas_price.to_bytes_le(); + if gas_price_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountFactoryError::FeeOutOfRange); + } + let gas_price = + u64::from_le_bytes(gas_price_bytes[..8].try_into().unwrap()); + + ((((overall_fee + gas_price - 1) / gas_price) as f64) * self.gas_estimate_multiplier) as u64 } }; @@ -575,10 +641,14 @@ where let gas_price = match self.gas_price { Some(gas_price) => gas_price, None => { - (((TryInto::::try_into(fee_estimate.gas_price) - .map_err(|_| AccountFactoryError::FeeOutOfRange)?) - as f64) - * self.gas_price_estimate_multiplier) as u128 + let gas_price_bytes = fee_estimate.gas_price.to_bytes_le(); + if gas_price_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(AccountFactoryError::FeeOutOfRange); + } + let gas_price = + u64::from_le_bytes(gas_price_bytes[..8].try_into().unwrap()); + + ((gas_price as f64) * self.gas_price_estimate_multiplier) as u128 } }; @@ -599,8 +669,10 @@ where async fn estimate_fee_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, ) -> Result> { + let skip_signature = self.factory.is_signer_interactive(); + let prepared = PreparedAccountDeploymentV3 { factory: self.factory, inner: RawAccountDeploymentV3 { @@ -611,7 +683,7 @@ where }, }; let deploy = prepared - .get_deploy_request() + .get_deploy_request(true, skip_signature) .await .map_err(AccountFactoryError::Signing)?; @@ -621,7 +693,13 @@ where BroadcastedTransaction::DeployAccount(BroadcastedDeployAccountTransaction::V3( deploy, )), - [], + if skip_signature { + // Validation would fail since real signature was not requested + vec![SimulationFlagForEstimateFee::SkipValidate] + } else { + // With the correct signature in place, run validation for accurate results + vec![] + }, self.factory.block_id(), ) .await @@ -630,10 +708,20 @@ where async fn simulate_with_nonce( &self, - nonce: FieldElement, + nonce: Felt, skip_validate: bool, skip_fee_charge: bool, ) -> Result> { + let skip_signature = if self.factory.is_signer_interactive() { + // If signer is interactive, we would try to minimize signing requests. However, if the + // caller has decided to not skip validation, it's best we still request a real + // signature, as otherwise the simulation would most likely fail. + skip_validate + } else { + // Signing with non-interactive signers is cheap so always request signatures. + false + }; + let prepared = PreparedAccountDeploymentV3 { factory: self.factory, inner: RawAccountDeploymentV3 { @@ -644,7 +732,7 @@ where }, }; let deploy = prepared - .get_deploy_request() + .get_deploy_request(true, skip_signature) .await .map_err(AccountFactoryError::Signing)?; @@ -672,39 +760,39 @@ where } impl RawAccountDeploymentV1 { - pub fn salt(&self) -> FieldElement { + pub const fn salt(&self) -> Felt { self.salt } - pub fn nonce(&self) -> FieldElement { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn max_fee(&self) -> FieldElement { + pub const fn max_fee(&self) -> Felt { self.max_fee } } impl RawAccountDeploymentV3 { - pub fn salt(&self) -> FieldElement { + pub const fn salt(&self) -> Felt { self.salt } - pub fn nonce(&self) -> FieldElement { + pub const fn nonce(&self) -> Felt { self.nonce } - pub fn gas(&self) -> u64 { + pub const fn gas(&self) -> u64 { self.gas } - pub fn gas_price(&self) -> u128 { + pub const fn gas_price(&self) -> u128 { self.gas_price } } impl<'f, F> PreparedAccountDeploymentV1<'f, F> { - pub fn from_raw(raw_deployment: RawAccountDeploymentV1, factory: &'f F) -> Self { + pub const fn from_raw(raw_deployment: RawAccountDeploymentV1, factory: &'f F) -> Self { Self { factory, inner: raw_deployment, @@ -713,7 +801,7 @@ impl<'f, F> PreparedAccountDeploymentV1<'f, F> { } impl<'f, F> PreparedAccountDeploymentV3<'f, F> { - pub fn from_raw(raw_deployment: RawAccountDeploymentV3, factory: &'f F) -> Self { + pub const fn from_raw(raw_deployment: RawAccountDeploymentV3, factory: &'f F) -> Self { Self { factory, inner: raw_deployment, @@ -726,7 +814,7 @@ where F: AccountFactory, { /// Locally calculates the target deployment address. - pub fn address(&self) -> FieldElement { + pub fn address(&self) -> Felt { calculate_contract_address( self.inner.salt, self.factory.class_hash(), @@ -734,15 +822,19 @@ where ) } - pub fn transaction_hash(&self) -> FieldElement { + pub fn transaction_hash(&self, query_only: bool) -> Felt { let mut calldata_to_hash = vec![self.factory.class_hash(), self.inner.salt]; calldata_to_hash.append(&mut self.factory.calldata()); compute_hash_on_elements(&[ PREFIX_DEPLOY_ACCOUNT, - FieldElement::ONE, // version + if query_only { + QUERY_VERSION_ONE + } else { + Felt::ONE + }, // version self.address(), - FieldElement::ZERO, // entry_point_selector + Felt::ZERO, // entry_point_selector compute_hash_on_elements(&calldata_to_hash), self.inner.max_fee, self.factory.chain_id(), @@ -754,7 +846,7 @@ where &self, ) -> Result> { let tx_request = self - .get_deploy_request() + .get_deploy_request(false, false) .await .map_err(AccountFactoryError::Signing)?; self.factory @@ -766,18 +858,23 @@ where async fn get_deploy_request( &self, + query_only: bool, + skip_signature: bool, ) -> Result { - let signature = self.factory.sign_deployment_v1(&self.inner).await?; - Ok(BroadcastedDeployAccountTransactionV1 { max_fee: self.inner.max_fee, - signature, + signature: if skip_signature { + vec![] + } else { + self.factory + .sign_deployment_v1(&self.inner, query_only) + .await? + }, nonce: self.inner.nonce, contract_address_salt: self.inner.salt, constructor_calldata: self.factory.calldata(), class_hash: self.factory.class_hash(), - // TODO: make use of query version tx for estimating fees - is_query: false, + is_query: query_only, }) } } @@ -787,7 +884,7 @@ where F: AccountFactory, { /// Locally calculates the target deployment address. - pub fn address(&self) -> FieldElement { + pub fn address(&self) -> Felt { calculate_contract_address( self.inner.salt, self.factory.class_hash(), @@ -795,18 +892,22 @@ where ) } - pub fn transaction_hash(&self) -> FieldElement { + pub fn transaction_hash(&self, query_only: bool) -> Felt { let mut hasher = PoseidonHasher::new(); hasher.update(PREFIX_DEPLOY_ACCOUNT); - hasher.update(FieldElement::THREE); + hasher.update(if query_only { + QUERY_VERSION_THREE + } else { + Felt::THREE + }); hasher.update(self.address()); hasher.update({ let mut fee_hasher = PoseidonHasher::new(); // Tip: fee market has not been been activated yet so it's hard-coded to be 0 - fee_hasher.update(FieldElement::ZERO); + fee_hasher.update(Felt::ZERO); let mut resource_buffer = [ 0, 0, b'L', b'1', b'_', b'G', b'A', b'S', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -814,14 +915,14 @@ where ]; resource_buffer[8..(8 + 8)].copy_from_slice(&self.inner.gas.to_be_bytes()); resource_buffer[(8 + 8)..].copy_from_slice(&self.inner.gas_price.to_be_bytes()); - fee_hasher.update(FieldElement::from_bytes_be(&resource_buffer).unwrap()); + fee_hasher.update(Felt::from_bytes_be(&resource_buffer)); // L2 resources are hard-coded to 0 let resource_buffer = [ 0, 0, b'L', b'2', b'_', b'G', b'A', b'S', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; - fee_hasher.update(FieldElement::from_bytes_be(&resource_buffer).unwrap()); + fee_hasher.update(Felt::from_bytes_be(&resource_buffer)); fee_hasher.finalize() }); @@ -833,7 +934,7 @@ where hasher.update(self.inner.nonce); // Hard-coded L1 DA mode for nonce and fee - hasher.update(FieldElement::ZERO); + hasher.update(Felt::ZERO); hasher.update({ let mut calldata_hasher = PoseidonHasher::new(); @@ -856,7 +957,7 @@ where &self, ) -> Result> { let tx_request = self - .get_deploy_request() + .get_deploy_request(false, false) .await .map_err(AccountFactoryError::Signing)?; self.factory @@ -868,11 +969,17 @@ where async fn get_deploy_request( &self, + query_only: bool, + skip_signature: bool, ) -> Result { - let signature = self.factory.sign_deployment_v3(&self.inner).await?; - Ok(BroadcastedDeployAccountTransactionV3 { - signature, + signature: if skip_signature { + vec![] + } else { + self.factory + .sign_deployment_v3(&self.inner, query_only) + .await? + }, nonce: self.inner.nonce, contract_address_salt: self.inner.salt, constructor_calldata: self.factory.calldata(), @@ -895,21 +1002,18 @@ where // Hard-coded L1 DA mode for nonce and fee nonce_data_availability_mode: DataAvailabilityMode::L1, fee_data_availability_mode: DataAvailabilityMode::L1, - // TODO: make use of query version tx for estimating fees - is_query: false, + is_query: query_only, }) } } -fn calculate_contract_address( - salt: FieldElement, - class_hash: FieldElement, - constructor_calldata: &[FieldElement], -) -> FieldElement { + +fn calculate_contract_address(salt: Felt, class_hash: Felt, constructor_calldata: &[Felt]) -> Felt { compute_hash_on_elements(&[ PREFIX_CONTRACT_ADDRESS, - FieldElement::ZERO, + Felt::ZERO, salt, class_hash, compute_hash_on_elements(constructor_calldata), - ]) % ADDR_BOUND + ]) + .mod_floor(&ADDR_BOUND) } diff --git a/starknet-accounts/src/factory/open_zeppelin.rs b/starknet-accounts/src/factory/open_zeppelin.rs index 343eaf90..8fa95022 100644 --- a/starknet-accounts/src/factory/open_zeppelin.rs +++ b/starknet-accounts/src/factory/open_zeppelin.rs @@ -4,14 +4,15 @@ use crate::{ }; use async_trait::async_trait; -use starknet_core::types::{BlockId, BlockTag, FieldElement}; +use starknet_core::types::{BlockId, BlockTag, Felt}; use starknet_providers::Provider; use starknet_signers::Signer; +#[derive(Debug)] pub struct OpenZeppelinAccountFactory { - class_hash: FieldElement, - chain_id: FieldElement, - public_key: FieldElement, + class_hash: Felt, + chain_id: Felt, + public_key: Felt, signer: S, provider: P, block_id: BlockId, @@ -22,8 +23,8 @@ where S: Signer, { pub async fn new( - class_hash: FieldElement, - chain_id: FieldElement, + class_hash: Felt, + chain_id: Felt, signer: S, provider: P, ) -> Result { @@ -54,15 +55,15 @@ where type Provider = P; type SignError = S::SignError; - fn class_hash(&self) -> FieldElement { + fn class_hash(&self) -> Felt { self.class_hash } - fn calldata(&self) -> Vec { + fn calldata(&self) -> Vec { vec![self.public_key] } - fn chain_id(&self) -> FieldElement { + fn chain_id(&self) -> Felt { self.chain_id } @@ -70,6 +71,10 @@ where &self.provider } + fn is_signer_interactive(&self) -> bool { + self.signer.is_interactive() + } + fn block_id(&self) -> BlockId { self.block_id } @@ -77,9 +82,10 @@ where async fn sign_deployment_v1( &self, deployment: &RawAccountDeploymentV1, - ) -> Result, Self::SignError> { - let tx_hash = - PreparedAccountDeploymentV1::from_raw(deployment.clone(), self).transaction_hash(); + query_only: bool, + ) -> Result, Self::SignError> { + let tx_hash = PreparedAccountDeploymentV1::from_raw(deployment.clone(), self) + .transaction_hash(query_only); let signature = self.signer.sign_hash(&tx_hash).await?; Ok(vec![signature.r, signature.s]) @@ -88,9 +94,10 @@ where async fn sign_deployment_v3( &self, deployment: &RawAccountDeploymentV3, - ) -> Result, Self::SignError> { - let tx_hash = - PreparedAccountDeploymentV3::from_raw(deployment.clone(), self).transaction_hash(); + query_only: bool, + ) -> Result, Self::SignError> { + let tx_hash = PreparedAccountDeploymentV3::from_raw(deployment.clone(), self) + .transaction_hash(query_only); let signature = self.signer.sign_hash(&tx_hash).await?; Ok(vec![signature.r, signature.s]) diff --git a/starknet-accounts/src/single_owner.rs b/starknet-accounts/src/single_owner.rs index 91d8acb2..4fc44ede 100644 --- a/starknet-accounts/src/single_owner.rs +++ b/starknet-accounts/src/single_owner.rs @@ -4,7 +4,7 @@ use crate::{ }; use async_trait::async_trait; -use starknet_core::types::{contract::ComputeClassHashError, BlockId, BlockTag, FieldElement}; +use starknet_core::types::{contract::ComputeClassHashError, BlockId, BlockTag, Felt}; use starknet_providers::Provider; use starknet_signers::Signer; @@ -16,8 +16,8 @@ where { provider: P, signer: S, - address: FieldElement, - chain_id: FieldElement, + address: Felt, + chain_id: Felt, block_id: BlockId, encoding: ExecutionEncoding, } @@ -54,11 +54,11 @@ where /// * `address`: Account contract address. /// * `chain_id`: Network chain ID. /// * `encoding`: How `__execute__` calldata should be encoded. - pub fn new( + pub const fn new( provider: P, signer: S, - address: FieldElement, - chain_id: FieldElement, + address: Felt, + chain_id: Felt, encoding: ExecutionEncoding, ) -> Self { Self { @@ -86,11 +86,11 @@ where { type SignError = SignError; - fn address(&self) -> FieldElement { + fn address(&self) -> Felt { self.address } - fn chain_id(&self) -> FieldElement { + fn chain_id(&self) -> Felt { self.chain_id } @@ -98,7 +98,7 @@ where &self, execution: &RawExecutionV1, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { let tx_hash = execution.transaction_hash(self.chain_id, self.address, query_only, self); let signature = self .signer @@ -113,7 +113,7 @@ where &self, execution: &RawExecutionV3, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { let tx_hash = execution.transaction_hash(self.chain_id, self.address, query_only, self); let signature = self .signer @@ -128,7 +128,7 @@ where &self, declaration: &RawDeclarationV2, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { let tx_hash = declaration.transaction_hash(self.chain_id, self.address, query_only); let signature = self .signer @@ -143,7 +143,7 @@ where &self, declaration: &RawDeclarationV3, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { let tx_hash = declaration.transaction_hash(self.chain_id, self.address, query_only); let signature = self .signer @@ -158,7 +158,7 @@ where &self, legacy_declaration: &RawLegacyDeclaration, query_only: bool, - ) -> Result, Self::SignError> { + ) -> Result, Self::SignError> { let tx_hash = legacy_declaration .transaction_hash(self.chain_id, self.address, query_only) .map_err(SignError::ClassHash)?; @@ -170,6 +170,10 @@ where Ok(vec![signature.r, signature.s]) } + + fn is_signer_interactive(&self) -> bool { + self.signer.is_interactive() + } } impl ExecutionEncoder for SingleOwnerAccount @@ -177,19 +181,19 @@ where P: Provider + Send, S: Signer + Send, { - fn encode_calls(&self, calls: &[Call]) -> Vec { - let mut execute_calldata: Vec = vec![calls.len().into()]; + fn encode_calls(&self, calls: &[Call]) -> Vec { + let mut execute_calldata: Vec = vec![calls.len().into()]; match self.encoding { ExecutionEncoding::Legacy => { - let mut concated_calldata: Vec = vec![]; - for call in calls.iter() { + let mut concated_calldata: Vec = vec![]; + for call in calls { execute_calldata.push(call.to); // to execute_calldata.push(call.selector); // selector execute_calldata.push(concated_calldata.len().into()); // data_offset execute_calldata.push(call.calldata.len().into()); // data_len - for item in call.calldata.iter() { + for item in &call.calldata { concated_calldata.push(*item); } } @@ -198,7 +202,7 @@ where execute_calldata.extend_from_slice(&concated_calldata); } ExecutionEncoding::New => { - for call in calls.iter() { + for call in calls { execute_calldata.push(call.to); // to execute_calldata.push(call.selector); // selector diff --git a/starknet-accounts/tests/single_owner_account.rs b/starknet-accounts/tests/single_owner_account.rs index fa5cbcee..46d895f4 100644 --- a/starknet-accounts/tests/single_owner_account.rs +++ b/starknet-accounts/tests/single_owner_account.rs @@ -7,7 +7,7 @@ use starknet_core::{ legacy::{LegacyContractClass, RawLegacyAbiEntry, RawLegacyFunction}, SierraClass, }, - BlockId, BlockTag, FieldElement, StarknetError, + BlockId, BlockTag, Felt, StarknetError, }, utils::get_selector_from_name, }; @@ -19,11 +19,11 @@ use starknet_signers::{LocalWallet, SigningKey}; use std::sync::Arc; /// Cairo short string encoding for `SN_SEPOLIA`. -const CHAIN_ID: FieldElement = FieldElement::from_mont([ - 1555806712078248243, - 18446744073708869172, - 18446744073709551615, +const CHAIN_ID: Felt = Felt::from_raw([ 507980251676163170, + 18446744073709551615, + 18446744073708869172, + 1555806712078248243, ]); fn create_sequencer_client() -> SequencerGatewayProvider { @@ -32,7 +32,7 @@ fn create_sequencer_client() -> SequencerGatewayProvider { fn create_jsonrpc_client() -> JsonRpcClient { let rpc_url = std::env::var("STARKNET_RPC") - .unwrap_or("https://juno.rpc.sepolia.starknet.rs/rpc/v0_7".into()); + .unwrap_or_else(|_| "https://juno.rpc.sepolia.starknet.rs/rpc/v0_7".into()); JsonRpcClient::new(HttpTransport::new(url::Url::parse(&rpc_url).unwrap())) } @@ -191,32 +191,24 @@ async fn can_declare_cairo0_contract_with_jsonrpc() { async fn can_get_nonce_inner(provider: P, address: &str) { let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be( - "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(), + Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), )); - let address = FieldElement::from_hex_be(address).unwrap(); + let address = Felt::from_hex(address).unwrap(); let mut account = SingleOwnerAccount::new(provider, signer, address, CHAIN_ID, ExecutionEncoding::New); account.set_block_id(BlockId::Tag(BlockTag::Pending)); - assert_ne!(account.get_nonce().await.unwrap(), FieldElement::ZERO); + assert_ne!(account.get_nonce().await.unwrap(), Felt::ZERO); } async fn can_estimate_invoke_v1_fee_inner(provider: P, address: &str) { let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be( - "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(), + Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), )); - let address = FieldElement::from_hex_be(address).unwrap(); - let eth_token_address = FieldElement::from_hex_be( - "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - ) - .unwrap(); + let address = Felt::from_hex(address).unwrap(); + let eth_token_address = + Felt::from_hex("049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7").unwrap(); let mut account = SingleOwnerAccount::new(provider, signer, address, CHAIN_ID, ExecutionEncoding::New); @@ -226,31 +218,22 @@ async fn can_estimate_invoke_v1_fee_inner(provider: P .execute_v1(vec![Call { to: eth_token_address, selector: get_selector_from_name("transfer").unwrap(), - calldata: vec![ - FieldElement::from_hex_be("0x1234").unwrap(), - FieldElement::ONE, - FieldElement::ZERO, - ], + calldata: vec![Felt::from_hex("0x1234").unwrap(), Felt::ONE, Felt::ZERO], }]) .estimate_fee() .await .unwrap(); - assert!(fee_estimate.overall_fee > FieldElement::ZERO); + assert!(fee_estimate.overall_fee > Felt::ZERO); } async fn can_estimate_invoke_v3_fee_inner(provider: P, address: &str) { let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be( - "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(), + Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), )); - let address = FieldElement::from_hex_be(address).unwrap(); - let eth_token_address = FieldElement::from_hex_be( - "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - ) - .unwrap(); + let address = Felt::from_hex(address).unwrap(); + let eth_token_address = + Felt::from_hex("049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7").unwrap(); let mut account = SingleOwnerAccount::new(provider, signer, address, CHAIN_ID, ExecutionEncoding::New); @@ -260,17 +243,13 @@ async fn can_estimate_invoke_v3_fee_inner(provider: P .execute_v3(vec![Call { to: eth_token_address, selector: get_selector_from_name("transfer").unwrap(), - calldata: vec![ - FieldElement::from_hex_be("0x1234").unwrap(), - FieldElement::ONE, - FieldElement::ZERO, - ], + calldata: vec![Felt::from_hex("0x1234").unwrap(), Felt::ONE, Felt::ZERO], }]) .estimate_fee() .await .unwrap(); - assert!(fee_estimate.overall_fee > FieldElement::ZERO); + assert!(fee_estimate.overall_fee > Felt::ZERO); } async fn can_parse_fee_estimation_error_inner( @@ -278,16 +257,11 @@ async fn can_parse_fee_estimation_error_inner( address: &str, ) { let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be( - "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(), + Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), )); - let address = FieldElement::from_hex_be(address).unwrap(); - let eth_token_address = FieldElement::from_hex_be( - "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - ) - .unwrap(); + let address = Felt::from_hex(address).unwrap(); + let eth_token_address = + Felt::from_hex("049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7").unwrap(); let mut account = SingleOwnerAccount::new(provider, signer, address, CHAIN_ID, ExecutionEncoding::New); @@ -299,8 +273,8 @@ async fn can_parse_fee_estimation_error_inner( selector: get_selector_from_name("transfer").unwrap(), calldata: vec![ address, - FieldElement::from_dec_str("1000000000000000000000").unwrap(), - FieldElement::ZERO, + Felt::from_dec_str("1000000000000000000000").unwrap(), + Felt::ZERO, ], }]) .estimate_fee() @@ -328,16 +302,11 @@ async fn can_execute_eth_transfer_invoke_v1_inner( // - poll the transaction hash until it's processed. let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be( - "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(), + Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), )); - let address = FieldElement::from_hex_be(address).unwrap(); - let eth_token_address = FieldElement::from_hex_be( - "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - ) - .unwrap(); + let address = Felt::from_hex(address).unwrap(); + let eth_token_address = + Felt::from_hex("049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7").unwrap(); let mut account = SingleOwnerAccount::new(provider, signer, address, CHAIN_ID, ExecutionEncoding::New); @@ -347,18 +316,14 @@ async fn can_execute_eth_transfer_invoke_v1_inner( .execute_v1(vec![Call { to: eth_token_address, selector: get_selector_from_name("transfer").unwrap(), - calldata: vec![ - FieldElement::from_hex_be("0x1234").unwrap(), - FieldElement::ONE, - FieldElement::ZERO, - ], + calldata: vec![Felt::from_hex("0x1234").unwrap(), Felt::ONE, Felt::ZERO], }]) - .max_fee(FieldElement::from_dec_str("1000000000000000000").unwrap()) + .max_fee(Felt::from_dec_str("1000000000000000000").unwrap()) .send() .await .unwrap(); - assert!(result.transaction_hash > FieldElement::ZERO); + assert!(result.transaction_hash > Felt::ZERO); } async fn can_execute_eth_transfer_invoke_v3_inner( @@ -373,16 +338,11 @@ async fn can_execute_eth_transfer_invoke_v3_inner( // - poll the transaction hash until it's processed. let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be( - "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(), + Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), )); - let address = FieldElement::from_hex_be(address).unwrap(); - let eth_token_address = FieldElement::from_hex_be( - "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - ) - .unwrap(); + let address = Felt::from_hex(address).unwrap(); + let eth_token_address = + Felt::from_hex("049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7").unwrap(); let mut account = SingleOwnerAccount::new(provider, signer, address, CHAIN_ID, ExecutionEncoding::New); @@ -392,11 +352,7 @@ async fn can_execute_eth_transfer_invoke_v3_inner( .execute_v3(vec![Call { to: eth_token_address, selector: get_selector_from_name("transfer").unwrap(), - calldata: vec![ - FieldElement::from_hex_be("0x1234").unwrap(), - FieldElement::ONE, - FieldElement::ZERO, - ], + calldata: vec![Felt::from_hex("0x1234").unwrap(), Felt::ONE, Felt::ZERO], }]) .gas(200000) .gas_price(500000000000000) @@ -404,7 +360,7 @@ async fn can_execute_eth_transfer_invoke_v3_inner( .await .unwrap(); - assert!(result.transaction_hash > FieldElement::ZERO); + assert!(result.transaction_hash > Felt::ZERO); } async fn can_execute_eth_transfer_invoke_v3_with_manual_gas_inner( @@ -416,16 +372,11 @@ async fn can_execute_eth_transfer_invoke_v3_with_manual_gas_inner FieldElement::ZERO); + assert!(result.transaction_hash > Felt::ZERO); } async fn can_declare_cairo1_contract_v2_inner( @@ -461,12 +412,9 @@ async fn can_declare_cairo1_contract_v2_inner( } let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be( - "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(), + Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), )); - let address = FieldElement::from_hex_be(address).unwrap(); + let address = Felt::from_hex(address).unwrap(); let mut account = SingleOwnerAccount::new(provider, signer, address, CHAIN_ID, ExecutionEncoding::New); account.set_block_id(BlockId::Tag(BlockTag::Pending)); @@ -494,16 +442,16 @@ async fn can_declare_cairo1_contract_v2_inner( let result = account .declare_v2( Arc::new(flattened_class), - FieldElement::from_hex_be(&hashes.compiled_class_hash).unwrap(), + Felt::from_hex(&hashes.compiled_class_hash).unwrap(), ) - .max_fee(FieldElement::from_dec_str("1000000000000000000").unwrap()) + .max_fee(Felt::from_dec_str("1000000000000000000").unwrap()) .send() .await .unwrap(); dbg!(&result); - assert!(result.transaction_hash > FieldElement::ZERO); + assert!(result.transaction_hash > Felt::ZERO); } async fn can_estimate_declare_v3_fee_inner(provider: P, address: &str) { @@ -513,12 +461,9 @@ async fn can_estimate_declare_v3_fee_inner(provider: } let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be( - "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(), + Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), )); - let address = FieldElement::from_hex_be(address).unwrap(); + let address = Felt::from_hex(address).unwrap(); let mut account = SingleOwnerAccount::new(provider, signer, address, CHAIN_ID, ExecutionEncoding::New); account.set_block_id(BlockId::Tag(BlockTag::Pending)); @@ -546,13 +491,13 @@ async fn can_estimate_declare_v3_fee_inner(provider: let result = account .declare_v3( Arc::new(flattened_class), - FieldElement::from_hex_be(&hashes.compiled_class_hash).unwrap(), + Felt::from_hex(&hashes.compiled_class_hash).unwrap(), ) .estimate_fee() .await .unwrap(); - assert!(result.overall_fee > FieldElement::ZERO); + assert!(result.overall_fee > Felt::ZERO); } async fn can_declare_cairo1_contract_v3_inner( @@ -567,12 +512,9 @@ async fn can_declare_cairo1_contract_v3_inner( } let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be( - "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(), + Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), )); - let address = FieldElement::from_hex_be(address).unwrap(); + let address = Felt::from_hex(address).unwrap(); let mut account = SingleOwnerAccount::new(provider, signer, address, CHAIN_ID, ExecutionEncoding::New); account.set_block_id(BlockId::Tag(BlockTag::Pending)); @@ -600,7 +542,7 @@ async fn can_declare_cairo1_contract_v3_inner( let result = account .declare_v3( Arc::new(flattened_class), - FieldElement::from_hex_be(&hashes.compiled_class_hash).unwrap(), + Felt::from_hex(&hashes.compiled_class_hash).unwrap(), ) .gas(200000) .gas_price(500000000000000) @@ -608,19 +550,16 @@ async fn can_declare_cairo1_contract_v3_inner( .await .unwrap(); - assert!(result.transaction_hash > FieldElement::ZERO); + assert!(result.transaction_hash > Felt::ZERO); } async fn can_declare_cairo0_contract_inner(provider: P, address: &str) { // This test case is not very useful, same as `can_execute_eth_transfer` above. let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be( - "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(), + Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), )); - let address = FieldElement::from_hex_be(address).unwrap(); + let address = Felt::from_hex(address).unwrap(); let mut account = SingleOwnerAccount::new(provider, signer, address, CHAIN_ID, ExecutionEncoding::New); account.set_block_id(BlockId::Tag(BlockTag::Pending)); @@ -647,10 +586,10 @@ async fn can_declare_cairo0_contract_inner(provider: let result = account .declare_legacy(Arc::new(contract_artifact)) - .max_fee(FieldElement::from_dec_str("1000000000000000000").unwrap()) + .max_fee(Felt::from_dec_str("1000000000000000000").unwrap()) .send() .await .unwrap(); - assert!(result.transaction_hash > FieldElement::ZERO); + assert!(result.transaction_hash > Felt::ZERO); } diff --git a/starknet-contract/Cargo.toml b/starknet-contract/Cargo.toml index 209bb59e..f6a89f3c 100644 --- a/starknet-contract/Cargo.toml +++ b/starknet-contract/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-contract" -version = "0.9.0" +version = "0.10.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -14,16 +14,19 @@ keywords = ["ethereum", "starknet", "web3"] exclude = ["test-data/**"] [dependencies] -starknet-core = { version = "0.10.0", path = "../starknet-core" } -starknet-providers = { version = "0.10.0", path = "../starknet-providers" } -starknet-accounts = { version = "0.9.0", path = "../starknet-accounts" } +starknet-core = { version = "0.11.1", path = "../starknet-core" } +starknet-providers = { version = "0.11.0", path = "../starknet-providers" } +starknet-accounts = { version = "0.10.0", path = "../starknet-accounts" } serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0.96" -serde_with = "2.3.2" +serde_with = "3.9.0" thiserror = "1.0.40" [dev-dependencies] rand = { version = "0.8.5", features=["std_rng"] } -starknet-signers = { version = "0.8.0", path = "../starknet-signers" } +starknet-signers = { version = "0.9.0", path = "../starknet-signers" } tokio = { version = "1.27.0", features = ["full"] } url = "2.3.1" + +[lints] +workspace = true diff --git a/starknet-contract/src/factory.rs b/starknet-contract/src/factory.rs index a57b6e70..299ff0f1 100644 --- a/starknet-contract/src/factory.rs +++ b/starknet-contract/src/factory.rs @@ -1,57 +1,60 @@ use starknet_accounts::{Account, AccountError, Call, ConnectedAccount, ExecutionV1, ExecutionV3}; use starknet_core::{ - types::{FeeEstimate, FieldElement, InvokeTransactionResult, SimulatedTransaction}, + types::{FeeEstimate, Felt, InvokeTransactionResult, SimulatedTransaction}, utils::{get_udc_deployed_address, UdcUniqueSettings, UdcUniqueness}, }; /// The default UDC address: 0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf. -const UDC_ADDRESS: FieldElement = FieldElement::from_mont([ - 15144800532519055890, - 15685625669053253235, - 9333317513348225193, +const UDC_ADDRESS: Felt = Felt::from_raw([ 121672436446604875, + 9333317513348225193, + 15685625669053253235, + 15144800532519055890, ]); /// Selector for entrypoint `deployContract`. -const SELECTOR_DEPLOYCONTRACT: FieldElement = FieldElement::from_mont([ - 18249998464715511309, - 1265649739554438882, - 1439621915307882061, +const SELECTOR_DEPLOYCONTRACT: Felt = Felt::from_raw([ 469988280392664069, + 1439621915307882061, + 1265649739554438882, + 18249998464715511309, ]); +#[derive(Debug)] pub struct ContractFactory { - class_hash: FieldElement, - udc_address: FieldElement, + class_hash: Felt, + udc_address: Felt, account: A, } /// Abstraction over contract deployment via the UDC. This type uses `INVOKE` v1 transactions under /// the hood, and hence pays transaction fees in ETH. To use v3 transactions for STRK fee payment, -/// use [DeploymentV3] instead. +/// use [`DeploymentV3`] instead. #[must_use] +#[derive(Debug)] pub struct DeploymentV1<'f, A> { factory: &'f ContractFactory, - constructor_calldata: Vec, - salt: FieldElement, + constructor_calldata: Vec, + salt: Felt, unique: bool, // The following fields allow us to mimic an `Execution` API. - nonce: Option, - max_fee: Option, + nonce: Option, + max_fee: Option, fee_estimate_multiplier: f64, } /// Abstraction over contract deployment via the UDC. This type uses `INVOKE` v3 transactions under /// the hood, and hence pays transaction fees in STRK. To use v1 transactions for ETH fee payment, -/// use [DeploymentV1] instead. +/// use [`DeploymentV1`] instead. #[must_use] +#[derive(Debug)] pub struct DeploymentV3<'f, A> { factory: &'f ContractFactory, - constructor_calldata: Vec, - salt: FieldElement, + constructor_calldata: Vec, + salt: Felt, unique: bool, // The following fields allow us to mimic an `Execution` API. - nonce: Option, + nonce: Option, gas: Option, gas_price: Option, gas_estimate_multiplier: f64, @@ -59,11 +62,11 @@ pub struct DeploymentV3<'f, A> { } impl ContractFactory { - pub fn new(class_hash: FieldElement, account: A) -> Self { + pub const fn new(class_hash: Felt, account: A) -> Self { Self::new_with_udc(class_hash, account, UDC_ADDRESS) } - pub fn new_with_udc(class_hash: FieldElement, account: A, udc_address: FieldElement) -> Self { + pub const fn new_with_udc(class_hash: Felt, account: A, udc_address: Felt) -> Self { Self { class_hash, udc_address, @@ -76,12 +79,12 @@ impl ContractFactory where A: Account, { - pub fn deploy_v1( + pub const fn deploy_v1( &self, - constructor_calldata: Vec, - salt: FieldElement, + constructor_calldata: Vec, + salt: Felt, unique: bool, - ) -> DeploymentV1 { + ) -> DeploymentV1<'_, A> { DeploymentV1 { factory: self, constructor_calldata, @@ -93,12 +96,12 @@ where } } - pub fn deploy_v3( + pub const fn deploy_v3( &self, - constructor_calldata: Vec, - salt: FieldElement, + constructor_calldata: Vec, + salt: Felt, unique: bool, - ) -> DeploymentV3 { + ) -> DeploymentV3<'_, A> { DeploymentV3 { factory: self, constructor_calldata, @@ -113,25 +116,25 @@ where } #[deprecated = "use version specific variants (`deploy_v1` & `deploy_v3`) instead"] - pub fn deploy( + pub const fn deploy( &self, - constructor_calldata: Vec, - salt: FieldElement, + constructor_calldata: Vec, + salt: Felt, unique: bool, - ) -> DeploymentV1 { + ) -> DeploymentV1<'_, A> { self.deploy_v1(constructor_calldata, salt, unique) } } impl<'f, A> DeploymentV1<'f, A> { - pub fn nonce(self, nonce: FieldElement) -> Self { + pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), ..self } } - pub fn max_fee(self, max_fee: FieldElement) -> Self { + pub fn max_fee(self, max_fee: Felt) -> Self { Self { max_fee: Some(max_fee), ..self @@ -147,7 +150,7 @@ impl<'f, A> DeploymentV1<'f, A> { } impl<'f, A> DeploymentV3<'f, A> { - pub fn nonce(self, nonce: FieldElement) -> Self { + pub fn nonce(self, nonce: Felt) -> Self { Self { nonce: Some(nonce), ..self @@ -188,7 +191,7 @@ where A: Account, { /// Calculate the resulting contract address without sending a transaction. - pub fn deployed_address(&self) -> FieldElement { + pub fn deployed_address(&self) -> Felt { get_udc_deployed_address( self.salt, self.factory.class_hash, @@ -210,7 +213,7 @@ where A: Account, { /// Calculate the resulting contract address without sending a transaction. - pub fn deployed_address(&self) -> FieldElement { + pub fn deployed_address(&self) -> Felt { get_udc_deployed_address( self.salt, self.factory.class_hash, @@ -232,7 +235,7 @@ where A: ConnectedAccount + Sync, { pub async fn estimate_fee(&self) -> Result> { - let execution: ExecutionV1 = self.into(); + let execution: ExecutionV1<'_, A> = self.into(); execution.estimate_fee().await } @@ -241,12 +244,12 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { - let execution: ExecutionV1 = self.into(); + let execution: ExecutionV1<'_, A> = self.into(); execution.simulate(skip_validate, skip_fee_charge).await } pub async fn send(&self) -> Result> { - let execution: ExecutionV1 = self.into(); + let execution: ExecutionV1<'_, A> = self.into(); execution.send().await } } @@ -256,7 +259,7 @@ where A: ConnectedAccount + Sync, { pub async fn estimate_fee(&self) -> Result> { - let execution: ExecutionV3 = self.into(); + let execution: ExecutionV3<'_, A> = self.into(); execution.estimate_fee().await } @@ -265,12 +268,12 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> Result> { - let execution: ExecutionV3 = self.into(); + let execution: ExecutionV3<'_, A> = self.into(); execution.simulate(skip_validate, skip_fee_charge).await } pub async fn send(&self) -> Result> { - let execution: ExecutionV3 = self.into(); + let execution: ExecutionV3<'_, A> = self.into(); execution.send().await } } @@ -280,11 +283,7 @@ impl<'f, A> From<&DeploymentV1<'f, A>> for ExecutionV1<'f, A> { let mut calldata = vec![ value.factory.class_hash, value.salt, - if value.unique { - FieldElement::ONE - } else { - FieldElement::ZERO - }, + if value.unique { Felt::ONE } else { Felt::ZERO }, value.constructor_calldata.len().into(), ]; calldata.extend_from_slice(&value.constructor_calldata); @@ -319,11 +318,7 @@ impl<'f, A> From<&DeploymentV3<'f, A>> for ExecutionV3<'f, A> { let mut calldata = vec![ value.factory.class_hash, value.salt, - if value.unique { - FieldElement::ONE - } else { - FieldElement::ZERO - }, + if value.unique { Felt::ONE } else { Felt::ZERO }, value.constructor_calldata.len().into(), ]; calldata.extend_from_slice(&value.constructor_calldata); @@ -373,17 +368,13 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_deployed_address_unique() { let factory = ContractFactory::new( - FieldElement::from_hex_be( - "0x2bfd9564754d9b4a326da62b2f22b8fea7bbeffd62da4fcaea986c323b7aeb", - ) - .unwrap(), + Felt::from_hex("0x2bfd9564754d9b4a326da62b2f22b8fea7bbeffd62da4fcaea986c323b7aeb") + .unwrap(), SingleOwnerAccount::new( SequencerGatewayProvider::starknet_alpha_sepolia(), LocalWallet::from_signing_key(SigningKey::from_random()), - FieldElement::from_hex_be( - "0xb1461de04c6a1aa3375bdf9b7723a8779c082ffe21311d683a0b15c078b5dc", - ) - .unwrap(), + Felt::from_hex("0xb1461de04c6a1aa3375bdf9b7723a8779c082ffe21311d683a0b15c078b5dc") + .unwrap(), chain_id::SEPOLIA, ExecutionEncoding::Legacy, ), @@ -391,62 +382,54 @@ mod tests { let unique_address_v1 = factory .deploy_v1( - vec![FieldElement::from_hex_be("0x1234").unwrap()], - FieldElement::from_hex_be("0x3456").unwrap(), + vec![Felt::from_hex("0x1234").unwrap()], + Felt::from_hex("0x3456").unwrap(), true, ) .deployed_address(); let unique_address_v3 = factory .deploy_v3( - vec![FieldElement::from_hex_be("0x1234").unwrap()], - FieldElement::from_hex_be("0x3456").unwrap(), + vec![Felt::from_hex("0x1234").unwrap()], + Felt::from_hex("0x3456").unwrap(), true, ) .deployed_address(); let not_unique_address_v1 = factory .deploy_v1( - vec![FieldElement::from_hex_be("0x1234").unwrap()], - FieldElement::from_hex_be("0x3456").unwrap(), + vec![Felt::from_hex("0x1234").unwrap()], + Felt::from_hex("0x3456").unwrap(), false, ) .deployed_address(); let not_unique_address_v3 = factory .deploy_v3( - vec![FieldElement::from_hex_be("0x1234").unwrap()], - FieldElement::from_hex_be("0x3456").unwrap(), + vec![Felt::from_hex("0x1234").unwrap()], + Felt::from_hex("0x3456").unwrap(), false, ) .deployed_address(); assert_eq!( unique_address_v1, - FieldElement::from_hex_be( - "0x36e05bcd41191387bc2f04ed9cad4776a75df3b748b0246a5d217a988474181" - ) - .unwrap() + Felt::from_hex("0x36e05bcd41191387bc2f04ed9cad4776a75df3b748b0246a5d217a988474181") + .unwrap() ); assert_eq!( unique_address_v3, - FieldElement::from_hex_be( - "0x36e05bcd41191387bc2f04ed9cad4776a75df3b748b0246a5d217a988474181" - ) - .unwrap() + Felt::from_hex("0x36e05bcd41191387bc2f04ed9cad4776a75df3b748b0246a5d217a988474181") + .unwrap() ); assert_eq!( not_unique_address_v1, - FieldElement::from_hex_be( - "0x3a320b6aa0b451b22fba90b5d75b943932649137c09a86a5cf4853031be70c1" - ) - .unwrap() + Felt::from_hex("0x3a320b6aa0b451b22fba90b5d75b943932649137c09a86a5cf4853031be70c1") + .unwrap() ); assert_eq!( not_unique_address_v3, - FieldElement::from_hex_be( - "0x3a320b6aa0b451b22fba90b5d75b943932649137c09a86a5cf4853031be70c1" - ) - .unwrap() + Felt::from_hex("0x3a320b6aa0b451b22fba90b5d75b943932649137c09a86a5cf4853031be70c1") + .unwrap() ); } } diff --git a/starknet-contract/tests/contract_deployment.rs b/starknet-contract/tests/contract_deployment.rs index b4bc6b0c..eff7f2cc 100644 --- a/starknet-contract/tests/contract_deployment.rs +++ b/starknet-contract/tests/contract_deployment.rs @@ -1,36 +1,30 @@ use rand::{rngs::StdRng, RngCore, SeedableRng}; use starknet_accounts::{ExecutionEncoding, SingleOwnerAccount}; use starknet_contract::ContractFactory; -use starknet_core::types::{ - contract::legacy::LegacyContractClass, BlockId, BlockTag, FieldElement, -}; +use starknet_core::types::{contract::legacy::LegacyContractClass, BlockId, BlockTag, Felt}; use starknet_providers::{jsonrpc::HttpTransport, JsonRpcClient}; use starknet_signers::{LocalWallet, SigningKey}; use url::Url; /// Cairo short string encoding for `SN_SEPOLIA`. -const CHAIN_ID: FieldElement = FieldElement::from_mont([ - 1555806712078248243, - 18446744073708869172, - 18446744073709551615, +const CHAIN_ID: Felt = Felt::from_raw([ 507980251676163170, + 18446744073709551615, + 18446744073708869172, + 1555806712078248243, ]); #[tokio::test] async fn can_deploy_contract_to_alpha_sepolia_with_invoke_v1() { let rpc_url = std::env::var("STARKNET_RPC") - .unwrap_or("https://pathfinder.rpc.sepolia.starknet.rs/rpc/v0_6".into()); + .unwrap_or_else(|_| "https://pathfinder.rpc.sepolia.starknet.rs/rpc/v0_6".into()); let provider = JsonRpcClient::new(HttpTransport::new(Url::parse(&rpc_url).unwrap())); let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be( - "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(), + Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), )); - let address = FieldElement::from_hex_be( - "0x059e738b86f82e11cd5b4afaccfce1d5166700c92fb87be59ad4af908e9bf866", - ) - .unwrap(); + let address = + Felt::from_hex("0x059e738b86f82e11cd5b4afaccfce1d5166700c92fb87be59ad4af908e9bf866") + .unwrap(); let mut account = SingleOwnerAccount::new(provider, signer, address, CHAIN_ID, ExecutionEncoding::New); account.set_block_id(BlockId::Tag(BlockTag::Pending)); @@ -47,12 +41,8 @@ async fn can_deploy_contract_to_alpha_sepolia_with_invoke_v1() { rng.fill_bytes(&mut salt_buffer[1..]); let result = factory - .deploy_v1( - vec![FieldElement::ONE], - FieldElement::from_bytes_be(&salt_buffer).unwrap(), - true, - ) - .max_fee(FieldElement::from_dec_str("100000000000000000").unwrap()) + .deploy_v1(vec![Felt::ONE], Felt::from_bytes_be(&salt_buffer), true) + .max_fee(Felt::from_dec_str("100000000000000000").unwrap()) .send() .await; @@ -65,18 +55,14 @@ async fn can_deploy_contract_to_alpha_sepolia_with_invoke_v1() { #[tokio::test] async fn can_deploy_contract_to_alpha_sepolia_with_invoke_v3() { let rpc_url = std::env::var("STARKNET_RPC") - .unwrap_or("https://pathfinder.rpc.sepolia.starknet.rs/rpc/v0_6".into()); + .unwrap_or_else(|_| "https://pathfinder.rpc.sepolia.starknet.rs/rpc/v0_6".into()); let provider = JsonRpcClient::new(HttpTransport::new(Url::parse(&rpc_url).unwrap())); let signer = LocalWallet::from(SigningKey::from_secret_scalar( - FieldElement::from_hex_be( - "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - ) - .unwrap(), + Felt::from_hex("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap(), )); - let address = FieldElement::from_hex_be( - "0x034dd51aa591d174b60d1cb45e46dfcae47946fae1c5e62933bbf48effedde4d", - ) - .unwrap(); + let address = + Felt::from_hex("0x034dd51aa591d174b60d1cb45e46dfcae47946fae1c5e62933bbf48effedde4d") + .unwrap(); let mut account = SingleOwnerAccount::new(provider, signer, address, CHAIN_ID, ExecutionEncoding::New); account.set_block_id(BlockId::Tag(BlockTag::Pending)); @@ -93,13 +79,9 @@ async fn can_deploy_contract_to_alpha_sepolia_with_invoke_v3() { rng.fill_bytes(&mut salt_buffer[1..]); let result = factory - .deploy_v3( - vec![FieldElement::ONE], - FieldElement::from_bytes_be(&salt_buffer).unwrap(), - true, - ) + .deploy_v3(vec![Felt::ONE], Felt::from_bytes_be(&salt_buffer), true) .gas(200000) - .gas_price(100000000000000) + .gas_price(500000000000000) .send() .await; diff --git a/starknet-core/Cargo.toml b/starknet-core/Cargo.toml index 6179c133..363ca0c7 100644 --- a/starknet-core/Cargo.toml +++ b/starknet-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-core" -version = "0.10.0" +version = "0.11.1" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -17,8 +17,7 @@ exclude = ["test-data/**"] all-features = true [dependencies] -starknet-crypto = { version = "0.6.2", path = "../starknet-crypto", default-features = false, features = ["alloc"] } -starknet-ff = { version = "0.3.7", path = "../starknet-ff", default-features = false, features = ["serde"] } +starknet-crypto = { version = "0.7.1", path = "../starknet-crypto", default-features = false, features = ["alloc"] } base64 = { version = "0.21.0", default-features = false, features = ["alloc"] } crypto-bigint = { version = "0.5.1", default-features = false } flate2 = { version = "1.0.25", optional = true } @@ -26,10 +25,12 @@ hex = { version = "0.4.3", default-features = false, features = ["alloc"] } serde = { version = "1.0.160", default-features = false, features = ["derive"] } serde_json = { version = "1.0.96", default-features = false, features = ["alloc", "raw_value"] } serde_json_pythonic = { version = "0.1.2", default-features = false, features = ["alloc", "raw_value"] } -serde_with = { version = "2.3.2", default-features = false, features = ["alloc", "macros"] } +serde_with = { version = "3.9.0", default-features = false, features = ["alloc", "macros"] } sha3 = { version = "0.10.7", default-features = false } +starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve", "serde", "num-traits"] } [dev-dependencies] +bincode = "1.3.3" criterion = { version = "0.4.0", default-features = false } hex-literal = "0.4.1" starknet-core = { path = ".", features = ["no_unknown_fields"] } @@ -39,9 +40,16 @@ wasm-bindgen-test = "0.3.34" [features] default = ["std"] -std = ["dep:flate2", "starknet-ff/std", "starknet-crypto/std"] +std = ["dep:flate2", "starknet-crypto/std", "starknet-types-core/std"] no_unknown_fields = [] [[bench]] -name = "class_hash" +name = "cairo0_class_hash" harness = false + +[[bench]] +name = "sierra_class_hash" +harness = false + +[lints] +workspace = true diff --git a/starknet-core/README.md b/starknet-core/README.md index 3ea1ed96..51ffb585 100644 --- a/starknet-core/README.md +++ b/starknet-core/README.md @@ -4,29 +4,31 @@ ## Benchmark -These results were generated on the author's machine with _AMD Ryzen 9 5950X 16-Core Processor_ running _Ubuntu 22.04.1 LTS_. +These results were generated on the author's machine with _Apple M3 Max_ running _macOS 14.5_. For instructions on running the benchmarks yourself, check out [this page](../BENCHMARK.md). ### Native ```log -class_hash time: [21.680 ms 21.684 ms 21.688 ms] +cairo0_class_hash time: [9.1665 ms 9.1690 ms 9.1718 ms] +sierra_class_hash time: [6.6931 ms 6.6944 ms 6.6958 ms] ``` ### WebAssembly -_(With its excellent wasm performance, results are only provided for Node.js here. Check out the [benchmark page](../BENCHMARK.md) for running the benchmark on other runtimes)._ +_(Results are only provided for `wasmtime` here. Check out the [benchmark page](../BENCHMARK.md) for running the benchmark on other runtimes)._ Runtime version: ```console -$ node --version -v18.16.0 +$ wasmtime --version +wasmtime-cli 21.0.1 (cedf9aa0f 2024-05-22) ``` -Node.js results: +`wasmtime` results: ```log -class_hash time: [124.48 ms 124.58 ms 124.69 ms] +cairo0_class_hash time: [36.515 ms 36.526 ms 36.538 ms] +sierra_class_hash time: [22.550 ms 22.557 ms 22.567 ms] ``` diff --git a/starknet-core/benches/class_hash.rs b/starknet-core/benches/cairo0_class_hash.rs similarity index 92% rename from starknet-core/benches/class_hash.rs rename to starknet-core/benches/cairo0_class_hash.rs index 27a2bedd..1fb2b607 100644 --- a/starknet-core/benches/class_hash.rs +++ b/starknet-core/benches/cairo0_class_hash.rs @@ -8,7 +8,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { )) .unwrap(); - c.bench_function("class_hash", |b| { + c.bench_function("cairo0_class_hash", |b| { b.iter(|| { black_box(&contract_artifact).class_hash().unwrap(); }); diff --git a/starknet-core/benches/sierra_class_hash.rs b/starknet-core/benches/sierra_class_hash.rs new file mode 100644 index 00000000..e36fca88 --- /dev/null +++ b/starknet-core/benches/sierra_class_hash.rs @@ -0,0 +1,18 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use starknet_core::types::contract::SierraClass; + +pub fn criterion_benchmark(c: &mut Criterion) { + let contract_artifact: SierraClass = serde_json::from_str(include_str!( + "../test-data/contracts/cairo1/artifacts/erc20_sierra.txt" + )) + .unwrap(); + + c.bench_function("sierra_class_hash", |b| { + b.iter(|| { + black_box(&contract_artifact).class_hash().unwrap(); + }); + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/starknet-core/src/chain_id.rs b/starknet-core/src/chain_id.rs index eac0ec51..715dc437 100644 --- a/starknet-core/src/chain_id.rs +++ b/starknet-core/src/chain_id.rs @@ -1,33 +1,33 @@ -use crate::types::FieldElement; +use starknet_types_core::felt::Felt; -pub const MAINNET: FieldElement = FieldElement::from_mont([ - 17696389056366564951, +pub const MAINNET: Felt = Felt::from_raw([ + 502562008147966918, 18446744073709551615, 18446744073709551615, - 502562008147966918, + 17696389056366564951, ]); #[deprecated = "The Goerli testnet has been shutdown"] -pub const TESTNET: FieldElement = FieldElement::from_mont([ - 3753493103916128178, - 18446744073709548950, - 18446744073709551615, +pub const TESTNET: Felt = Felt::from_raw([ 398700013197595345, + 18446744073709551615, + 18446744073709548950, + 3753493103916128178, ]); #[deprecated = "The Goerli testnet has been shutdown"] -pub const TESTNET2: FieldElement = FieldElement::from_mont([ - 1663542769632127759, - 18446744073708869172, - 18446744073709551615, +pub const TESTNET2: Felt = Felt::from_raw([ 33650220878420990, + 18446744073709551615, + 18446744073708869172, + 1663542769632127759, ]); -pub const SEPOLIA: FieldElement = FieldElement::from_mont([ - 1555806712078248243, - 18446744073708869172, - 18446744073709551615, +pub const SEPOLIA: Felt = Felt::from_raw([ 507980251676163170, + 18446744073709551615, + 18446744073708869172, + 1555806712078248243, ]); #[cfg(test)] @@ -45,9 +45,7 @@ mod test { ("SN_GOERLI", TESTNET), ("SN_GOERLI2", TESTNET2), ("SN_SEPOLIA", SEPOLIA), - ] - .into_iter() - { + ] { assert_eq!(cairo_short_string_to_felt(text).unwrap(), felt); } } diff --git a/starknet-core/src/crypto.rs b/starknet-core/src/crypto.rs index e703fc24..1977f4da 100644 --- a/starknet-core/src/crypto.rs +++ b/starknet-core/src/crypto.rs @@ -1,4 +1,4 @@ -use crate::types::FieldElement; +use starknet_types_core::felt::Felt; pub use starknet_crypto::{pedersen_hash, ExtendedSignature, Signature}; use starknet_crypto::{rfc6979_generate_k, sign, verify, SignError, VerifyError}; @@ -46,20 +46,25 @@ mod errors { } pub use errors::{EcdsaSignError, EcdsaVerifyError}; -pub fn compute_hash_on_elements(data: &[FieldElement]) -> FieldElement { - let mut current_hash = FieldElement::ZERO; - - for item in data.iter() { - current_hash = pedersen_hash(¤t_hash, item); +pub fn compute_hash_on_elements<'a, ESI, II>(data: II) -> Felt +where + ESI: ExactSizeIterator, + II: IntoIterator, +{ + let mut current_hash = Felt::ZERO; + let data_iter = data.into_iter(); + let data_len = Felt::from(data_iter.len()); + + for elem in data_iter { + current_hash = pedersen_hash(¤t_hash, elem); } - let data_len = FieldElement::from(data.len()); pedersen_hash(¤t_hash, &data_len) } pub fn ecdsa_sign( - private_key: &FieldElement, - message_hash: &FieldElement, + private_key: &Felt, + message_hash: &Felt, ) -> Result { // Seed-retry logic ported from `cairo-lang` let mut seed = None; @@ -76,8 +81,8 @@ pub fn ecdsa_sign( Err(SignError::InvalidK) => { // Bump seed and retry seed = match seed { - Some(prev_seed) => Some(prev_seed + FieldElement::ONE), - None => Some(FieldElement::ONE), + Some(prev_seed) => Some(prev_seed + Felt::ONE), + None => Some(Felt::ONE), }; } }; @@ -85,8 +90,8 @@ pub fn ecdsa_sign( } pub fn ecdsa_verify( - public_key: &FieldElement, - message_hash: &FieldElement, + public_key: &Felt, + message_hash: &Felt, signature: &Signature, ) -> Result { match verify(public_key, message_hash, &signature.r, &signature.s) { @@ -107,15 +112,14 @@ mod tests { fn test_compute_hash_on_elements() { // Generated with `cairo-lang` let hash = compute_hash_on_elements(&[ - FieldElement::from_hex_be("0xaa").unwrap(), - FieldElement::from_hex_be("0xbb").unwrap(), - FieldElement::from_hex_be("0xcc").unwrap(), - FieldElement::from_hex_be("0xdd").unwrap(), + Felt::from_hex("0xaa").unwrap(), + Felt::from_hex("0xbb").unwrap(), + Felt::from_hex("0xcc").unwrap(), + Felt::from_hex("0xdd").unwrap(), ]); - let expected_hash = FieldElement::from_hex_be( - "025cde77210b1c223b2c6e69db6e9021aa1599177ab177474d5326cd2a62cb69", - ) - .unwrap(); + let expected_hash = + Felt::from_hex("025cde77210b1c223b2c6e69db6e9021aa1599177ab177474d5326cd2a62cb69") + .unwrap(); assert_eq!(expected_hash, hash); } @@ -125,10 +129,9 @@ mod tests { fn test_compute_hash_on_elements_empty_data() { // Generated with `cairo-lang` let hash = compute_hash_on_elements(&[]); - let expected_hash = FieldElement::from_hex_be( - "049ee3eba8c1600700ee1b87eb599f16716b0b1022947733551fde4050ca6804", - ) - .unwrap(); + let expected_hash = + Felt::from_hex("049ee3eba8c1600700ee1b87eb599f16716b0b1022947733551fde4050ca6804") + .unwrap(); assert_eq!(expected_hash, hash); } @@ -138,24 +141,18 @@ mod tests { fn test_ecdsa_sign() { // Generated with `cairo-lang` let signature = ecdsa_sign( - &FieldElement::from_hex_be( - "0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79", - ) - .unwrap(), - &FieldElement::from_hex_be( - "06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76", - ) - .unwrap(), - ) - .unwrap(); - let expected_r = FieldElement::from_hex_be( - "061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f", - ) - .unwrap(); - let expected_s = FieldElement::from_hex_be( - "04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a", + &Felt::from_hex("0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79") + .unwrap(), + &Felt::from_hex("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76") + .unwrap(), ) .unwrap(); + let expected_r = + Felt::from_hex("061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f") + .unwrap(); + let expected_s = + Felt::from_hex("04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a") + .unwrap(); assert_eq!(signature.r, expected_r); assert_eq!(signature.s, expected_s); @@ -165,14 +162,10 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_ecdsa_sign_message_hash_out_of_range() { match ecdsa_sign( - &FieldElement::from_hex_be( - "0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79", - ) - .unwrap(), - &FieldElement::from_hex_be( - "0800000000000000000000000000000000000000000000000000000000000000", - ) - .unwrap(), + &Felt::from_hex("0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79") + .unwrap(), + &Felt::from_hex("0800000000000000000000000000000000000000000000000000000000000000") + .unwrap(), ) { Err(EcdsaSignError::MessageHashOutOfRange) => {} _ => panic!("Should throw error on out of range message hash"), @@ -183,22 +176,16 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_ecdsa_verify_valid_signature() { // Generated with `cairo-lang` - let public_key = FieldElement::from_hex_be( - "02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159", - ) - .unwrap(); - let message_hash = FieldElement::from_hex_be( - "06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76", - ) - .unwrap(); - let r = FieldElement::from_hex_be( - "061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f", - ) - .unwrap(); - let s = FieldElement::from_hex_be( - "04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a", - ) - .unwrap(); + let public_key = + Felt::from_hex("02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159") + .unwrap(); + let message_hash = + Felt::from_hex("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76") + .unwrap(); + let r = Felt::from_hex("061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f") + .unwrap(); + let s = Felt::from_hex("04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a") + .unwrap(); assert!(ecdsa_verify(&public_key, &message_hash, &Signature { r, s }).unwrap()); } @@ -207,22 +194,16 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_ecdsa_verify_invalid_signature() { // Generated with `cairo-lang` - let public_key = FieldElement::from_hex_be( - "02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159", - ) - .unwrap(); - let message_hash = FieldElement::from_hex_be( - "06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76", - ) - .unwrap(); - let r = FieldElement::from_hex_be( - "061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f", - ) - .unwrap(); - let s = FieldElement::from_hex_be( - "04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9b", - ) - .unwrap(); + let public_key = + Felt::from_hex("02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159") + .unwrap(); + let message_hash = + Felt::from_hex("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76") + .unwrap(); + let r = Felt::from_hex("061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f") + .unwrap(); + let s = Felt::from_hex("04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9b") + .unwrap(); assert!(!ecdsa_verify(&public_key, &message_hash, &Signature { r, s }).unwrap()); } diff --git a/starknet-core/src/serde/byte_array.rs b/starknet-core/src/serde/byte_array.rs index 9d171396..0d2bb46e 100644 --- a/starknet-core/src/serde/byte_array.rs +++ b/starknet-core/src/serde/byte_array.rs @@ -24,7 +24,7 @@ pub mod base64 { impl<'de> Visitor<'de> for Base64Visitor { type Value = Vec; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string") } diff --git a/starknet-core/src/serde/num_hex.rs b/starknet-core/src/serde/num_hex.rs index 985b9053..f285a18a 100644 --- a/starknet-core/src/serde/num_hex.rs +++ b/starknet-core/src/serde/num_hex.rs @@ -9,21 +9,29 @@ pub mod u64 { where S: Serializer, { - serializer.serialize_str(&format!("{value:#x}")) + if serializer.is_human_readable() { + serializer.serialize_str(&format!("{value:#x}")) + } else { + serializer.serialize_u64(*value) + } } pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { - deserializer.deserialize_any(NumHexVisitor) + if deserializer.is_human_readable() { + deserializer.deserialize_str(NumHexVisitor) + } else { + deserializer.deserialize_u64(NumHexVisitor) + } } impl<'de> Visitor<'de> for NumHexVisitor { type Value = u64; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { - write!(formatter, "string") + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { + write!(formatter, "string, or an array of u8") } fn visit_str(self, v: &str) -> Result @@ -33,5 +41,37 @@ pub mod u64 { u64::from_str_radix(v.trim_start_matches("0x"), 16) .map_err(|err| serde::de::Error::custom(format!("invalid u64 hex string: {err}"))) } + + fn visit_u64(self, v: u64) -> Result + where + E: serde::de::Error, + { + Ok(v) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use hex_literal::hex; + use serde::{Deserialize, Serialize}; + + #[derive(Serialize, Deserialize)] + struct TestStruct(#[serde(with = "u64")] pub u64); + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_ser() { + let r = bincode::serialize(&TestStruct(0x1234)).unwrap(); + assert_eq!(r, hex!("3412000000000000")); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_deser() { + let r = bincode::deserialize::(&hex!("3412000000000000")).unwrap(); + assert_eq!(r.0, 0x1234); } } diff --git a/starknet-core/src/serde/unsigned_field_element.rs b/starknet-core/src/serde/unsigned_field_element.rs index 1a4d8a53..87f311cb 100644 --- a/starknet-core/src/serde/unsigned_field_element.rs +++ b/starknet-core/src/serde/unsigned_field_element.rs @@ -1,82 +1,117 @@ use alloc::{fmt::Formatter, format}; +use crypto_bigint::U256; use serde::{ de::{Error as DeError, Visitor}, Deserializer, Serializer, }; use serde_with::{DeserializeAs, SerializeAs}; -use crate::types::FieldElement; +use starknet_types_core::felt::Felt; +const PRIME: U256 = + U256::from_be_hex("0800000000000011000000000000000000000000000000000000000000000001"); + +#[derive(Debug)] pub struct UfeHex; +#[derive(Debug)] pub struct UfeHexOption; +#[derive(Debug)] pub struct UfePendingBlockHash; struct UfeHexVisitor; struct UfeHexOptionVisitor; struct UfePendingBlockHashVisitor; -impl SerializeAs for UfeHex { - fn serialize_as(value: &FieldElement, serializer: S) -> Result +impl SerializeAs for UfeHex { + fn serialize_as(value: &Felt, serializer: S) -> Result where S: Serializer, { - serializer.serialize_str(&format!("{value:#x}")) + if serializer.is_human_readable() { + serializer.serialize_str(&format!("{value:#x}")) + } else { + serializer.serialize_bytes(&value.to_bytes_be()) + } } } -impl<'de> DeserializeAs<'de, FieldElement> for UfeHex { - fn deserialize_as(deserializer: D) -> Result +impl<'de> DeserializeAs<'de, Felt> for UfeHex { + fn deserialize_as(deserializer: D) -> Result where D: Deserializer<'de>, { - deserializer.deserialize_any(UfeHexVisitor) + if deserializer.is_human_readable() { + deserializer.deserialize_any(UfeHexVisitor) + } else { + deserializer.deserialize_bytes(UfeHexVisitor) + } } } impl<'de> Visitor<'de> for UfeHexVisitor { - type Value = FieldElement; + type Value = Felt; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { - write!(formatter, "string") + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { + write!(formatter, "a hex string, or an array of u8") } fn visit_str(self, v: &str) -> Result where E: DeError, { - FieldElement::from_hex_be(v) - .map_err(|err| DeError::custom(format!("invalid hex string: {err}"))) + Felt::from_hex(v).map_err(|err| DeError::custom(format!("invalid hex string: {err}"))) + } + + fn visit_bytes(self, v: &[u8]) -> Result { + let buf = <[u8; 32]>::try_from(v).map_err(serde::de::Error::custom)?; + + if U256::from_be_slice(&buf) < PRIME { + Ok(Felt::from_bytes_be(&buf)) + } else { + Err(serde::de::Error::custom("field element value out of range")) + } } } -impl SerializeAs> for UfeHexOption { - fn serialize_as(value: &Option, serializer: S) -> Result +impl SerializeAs> for UfeHexOption { + fn serialize_as(value: &Option, serializer: S) -> Result where S: Serializer, { - match value { - Some(value) => serializer.serialize_str(&format!("{value:#064x}")), - None => serializer.serialize_none(), + if serializer.is_human_readable() { + match value { + Some(value) => serializer.serialize_str(&format!("{value:#064x}")), + None => serializer.serialize_none(), + } + } else { + match value { + Some(value) => serializer.serialize_bytes(&value.to_bytes_be()), + None => serializer.serialize_bytes(&[]), + } } } } -impl<'de> DeserializeAs<'de, Option> for UfeHexOption { - fn deserialize_as(deserializer: D) -> Result, D::Error> +impl<'de> DeserializeAs<'de, Option> for UfeHexOption { + fn deserialize_as(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { - deserializer.deserialize_any(UfeHexOptionVisitor) + if deserializer.is_human_readable() { + deserializer.deserialize_any(UfeHexOptionVisitor) + } else { + deserializer.deserialize_bytes(UfeHexOptionVisitor) + } } } impl<'de> Visitor<'de> for UfeHexOptionVisitor { - type Value = Option; + type Value = Option; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string") } @@ -86,40 +121,65 @@ impl<'de> Visitor<'de> for UfeHexOptionVisitor { { match v { "" => Ok(None), - _ => match FieldElement::from_hex_be(v) { + _ => match Felt::from_hex(v) { Ok(value) => Ok(Some(value)), Err(err) => Err(DeError::custom(format!("invalid hex string: {err}"))), }, } } + + fn visit_bytes(self, v: &[u8]) -> Result { + if v.is_empty() { + return Ok(None); + } + + let buf = <[u8; 32]>::try_from(v).map_err(serde::de::Error::custom)?; + + if U256::from_be_slice(&buf) < PRIME { + Ok(Some(Felt::from_bytes_be(&buf))) + } else { + Err(serde::de::Error::custom("field element value out of range")) + } + } } -impl SerializeAs> for UfePendingBlockHash { - fn serialize_as(value: &Option, serializer: S) -> Result +impl SerializeAs> for UfePendingBlockHash { + fn serialize_as(value: &Option, serializer: S) -> Result where S: Serializer, { - match value { - Some(value) => serializer.serialize_str(&format!("{value:#064x}")), - // We don't know if it's `null` or `"pending"` - None => serializer.serialize_none(), + if serializer.is_human_readable() { + match value { + Some(value) => serializer.serialize_str(&format!("{value:#064x}")), + // We don't know if it's `null` or `"pending"` + None => serializer.serialize_none(), + } + } else { + match value { + Some(value) => serializer.serialize_bytes(&value.to_bytes_be()), + None => serializer.serialize_bytes(&[]), + } } } } -impl<'de> DeserializeAs<'de, Option> for UfePendingBlockHash { - fn deserialize_as(deserializer: D) -> Result, D::Error> +impl<'de> DeserializeAs<'de, Option> for UfePendingBlockHash { + fn deserialize_as(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { - deserializer.deserialize_any(UfePendingBlockHashVisitor) + if deserializer.is_human_readable() { + deserializer.deserialize_any(UfePendingBlockHashVisitor) + } else { + deserializer.deserialize_bytes(UfePendingBlockHashVisitor) + } } } impl<'de> Visitor<'de> for UfePendingBlockHashVisitor { - type Value = Option; + type Value = Option; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string") } @@ -130,29 +190,121 @@ impl<'de> Visitor<'de> for UfePendingBlockHashVisitor { if v.is_empty() || v == "pending" || v == "None" { Ok(None) } else { - match FieldElement::from_hex_be(v) { + match Felt::from_hex(v) { Ok(value) => Ok(Some(value)), Err(err) => Err(DeError::custom(format!("invalid hex string: {err}"))), } } } + + fn visit_bytes(self, v: &[u8]) -> Result { + if v.is_empty() { + return Ok(None); + } + + let buf = <[u8; 32]>::try_from(v).map_err(serde::de::Error::custom)?; + + if U256::from_be_slice(&buf) < PRIME { + Ok(Some(Felt::from_bytes_be(&buf))) + } else { + Err(serde::de::Error::custom("field element value out of range")) + } + } } #[cfg(test)] mod tests { use super::*; - use serde::Deserialize; + use hex_literal::hex; + use serde::{Deserialize, Serialize}; use serde_with::serde_as; #[serde_as] - #[derive(Deserialize)] - struct TestStruct(#[serde_as(as = "UfeHexOption")] pub Option); + #[derive(Serialize, Deserialize)] + struct TestStruct(#[serde_as(as = "UfeHex")] pub Felt); + + #[serde_as] + #[derive(Serialize, Deserialize)] + struct TestOptionStruct(#[serde_as(as = "UfeHexOption")] pub Option); + + #[serde_as] + #[derive(Serialize, Deserialize)] + struct TestBlockHashStruct(#[serde_as(as = "UfePendingBlockHash")] pub Option); + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_ser() { + let r = bincode::serialize(&TestStruct(Felt::ONE)).unwrap(); + assert_eq!( + r, + hex!( + "2000000000000000 0000000000000000000000000000000000000000000000000000000000000001" + ) + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_deser() { + let r = bincode::deserialize::(&hex!( + "2000000000000000 0000000000000000000000000000000000000000000000000000000000000001" + )) + .unwrap(); + assert_eq!(r.0, Felt::ONE); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_deser_out_of_range() { + if bincode::deserialize::(&hex!( + "2000000000000000 0800000000000011000000000000000000000000000000000000000000000001" + )) + .is_ok() + { + panic!("deserialization should fail") + } + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn option_deser_empty_string() { + let r = serde_json::from_str::("\"\"").unwrap(); + assert_eq!(r.0, None); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn option_bin_ser_none() { + let r = bincode::serialize(&TestOptionStruct(None)).unwrap(); + assert_eq!(r, hex!("0000000000000000")); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn option_bin_deser_none() { + let r = bincode::deserialize::(&hex!("0000000000000000")).unwrap(); + assert_eq!(r.0, None); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn pending_block_hash_deser_pending() { + let r = serde_json::from_str::("\"pending\"").unwrap(); + assert_eq!(r.0, None); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn pending_block_hash_bin_ser_none() { + let r = bincode::serialize(&TestBlockHashStruct(None)).unwrap(); + assert_eq!(r, hex!("0000000000000000")); + } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn empty_string_deser() { - let r = serde_json::from_str::("\"\"").unwrap(); + fn pending_block_hash_bin_deser_none() { + let r = bincode::deserialize::(&hex!("0000000000000000")).unwrap(); assert_eq!(r.0, None); } } diff --git a/starknet-core/src/types/codegen.rs b/starknet-core/src/types/codegen.rs index b10d4976..2d7e0d02 100644 --- a/starknet-core/src/types/codegen.rs +++ b/starknet-core/src/types/codegen.rs @@ -3,7 +3,7 @@ // https://github.com/xJonathanLEI/starknet-jsonrpc-codegen // Code generated with version: -// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen#2fc8455d3720039015a9abf014c27ea3ca24bd25 +// https://github.com/xJonathanLEI/starknet-jsonrpc-codegen#fbd3aed2a08d6b29328e87ee0bbfb7e80f7051b0 // These types are ignored from code generation. Implement them manually: // - `RECEIPT_BLOCK` @@ -24,6 +24,9 @@ // - `TXN` // - `TXN_RECEIPT` +#![allow(clippy::doc_markdown)] +#![allow(clippy::missing_const_for_fn)] + use alloc::{format, string::*, vec::*}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -38,11 +41,11 @@ pub type OwnedPtr = alloc::sync::Arc; #[cfg(not(target_has_atomic = "ptr"))] pub type OwnedPtr = alloc::boxed::Box; -const QUERY_VERSION_OFFSET: FieldElement = FieldElement::from_mont([ - 18446744073700081665, - 17407, - 18446744073709551584, +const QUERY_VERSION_OFFSET: Felt = Felt::from_raw([ 576460752142434320, + 18446744073709551584, + 17407, + 18446744073700081665, ]); /// Block status. @@ -82,20 +85,20 @@ pub struct BlockWithReceipts { pub status: BlockStatus, /// Block hash #[serde_as(as = "UfeHex")] - pub block_hash: FieldElement, + pub block_hash: Felt, /// The hash of this block's parent #[serde_as(as = "UfeHex")] - pub parent_hash: FieldElement, + pub parent_hash: Felt, /// The block number (its height) pub block_number: u64, /// The new global state root #[serde_as(as = "UfeHex")] - pub new_root: FieldElement, + pub new_root: Felt, /// The time in which the block was created, encoded in Unix time pub timestamp: u64, /// The Starknet identity of the sequencer submitting this block #[serde_as(as = "UfeHex")] - pub sequencer_address: FieldElement, + pub sequencer_address: Felt, /// The price of L1 gas in the block pub l1_gas_price: ResourcePrice, /// The price of L1 data gas in the block @@ -119,20 +122,20 @@ pub struct BlockWithTxHashes { pub status: BlockStatus, /// Block hash #[serde_as(as = "UfeHex")] - pub block_hash: FieldElement, + pub block_hash: Felt, /// The hash of this block's parent #[serde_as(as = "UfeHex")] - pub parent_hash: FieldElement, + pub parent_hash: Felt, /// The block number (its height) pub block_number: u64, /// The new global state root #[serde_as(as = "UfeHex")] - pub new_root: FieldElement, + pub new_root: Felt, /// The time in which the block was created, encoded in Unix time pub timestamp: u64, /// The Starknet identity of the sequencer submitting this block #[serde_as(as = "UfeHex")] - pub sequencer_address: FieldElement, + pub sequencer_address: Felt, /// The price of L1 gas in the block pub l1_gas_price: ResourcePrice, /// The price of L1 data gas in the block @@ -143,7 +146,7 @@ pub struct BlockWithTxHashes { pub starknet_version: String, /// The hashes of the transactions included in this block #[serde_as(as = "Vec")] - pub transactions: Vec, + pub transactions: Vec, } /// Block with transactions. @@ -157,20 +160,20 @@ pub struct BlockWithTxs { pub status: BlockStatus, /// Block hash #[serde_as(as = "UfeHex")] - pub block_hash: FieldElement, + pub block_hash: Felt, /// The hash of this block's parent #[serde_as(as = "UfeHex")] - pub parent_hash: FieldElement, + pub parent_hash: Felt, /// The block number (its height) pub block_number: u64, /// The new global state root #[serde_as(as = "UfeHex")] - pub new_root: FieldElement, + pub new_root: Felt, /// The time in which the block was created, encoded in Unix time pub timestamp: u64, /// The Starknet identity of the sequencer submitting this block #[serde_as(as = "UfeHex")] - pub sequencer_address: FieldElement, + pub sequencer_address: Felt, /// The price of L1 gas in the block pub l1_gas_price: ResourcePrice, /// The price of L1 data gas in the block @@ -187,13 +190,13 @@ pub struct BlockWithTxs { #[derive(Debug, Clone, PartialEq, Eq)] pub struct BroadcastedDeclareTransactionV1 { /// The address of the account contract sending the declaration transaction - pub sender_address: FieldElement, + pub sender_address: Felt, /// The maximal fee that can be charged for including the transaction - pub max_fee: FieldElement, + pub max_fee: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// The class to be declared pub contract_class: OwnedPtr, /// If set to `true`, uses a query-only transaction version that's invalid for execution @@ -206,15 +209,15 @@ pub struct BroadcastedDeclareTransactionV1 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct BroadcastedDeclareTransactionV2 { /// The address of the account contract sending the declaration transaction - pub sender_address: FieldElement, + pub sender_address: Felt, /// The hash of the cairo assembly resulting from the sierra compilation - pub compiled_class_hash: FieldElement, + pub compiled_class_hash: Felt, /// The maximal fee that can be charged for including the transaction - pub max_fee: FieldElement, + pub max_fee: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// The class to be declared pub contract_class: OwnedPtr, /// If set to `true`, uses a query-only transaction version that's invalid for execution @@ -227,13 +230,13 @@ pub struct BroadcastedDeclareTransactionV2 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct BroadcastedDeclareTransactionV3 { /// The address of the account contract sending the declaration transaction - pub sender_address: FieldElement, + pub sender_address: Felt, /// The hash of the cairo assembly resulting from the sierra compilation - pub compiled_class_hash: FieldElement, + pub compiled_class_hash: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// The class to be declared pub contract_class: OwnedPtr, /// Resource bounds for the transaction execution @@ -241,9 +244,9 @@ pub struct BroadcastedDeclareTransactionV3 { /// The tip for the transaction pub tip: u64, /// Data needed to allow the paymaster to pay for the transaction in native tokens - pub paymaster_data: Vec, + pub paymaster_data: Vec, /// Data needed to deploy the account contract from which this tx will be initiated - pub account_deployment_data: Vec, + pub account_deployment_data: Vec, /// The storage domain of the account's nonce (an account has a nonce per da mode) pub nonce_data_availability_mode: DataAvailabilityMode, /// The storage domain of the account's balance from which fee will be charged @@ -258,17 +261,17 @@ pub struct BroadcastedDeclareTransactionV3 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct BroadcastedDeployAccountTransactionV1 { /// The maximal fee that can be charged for including the transaction - pub max_fee: FieldElement, + pub max_fee: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// The salt for the address of the deployed contract - pub contract_address_salt: FieldElement, + pub contract_address_salt: Felt, /// The parameters passed to the constructor - pub constructor_calldata: Vec, + pub constructor_calldata: Vec, /// The hash of the deployed contract's class - pub class_hash: FieldElement, + pub class_hash: Felt, /// If set to `true`, uses a query-only transaction version that's invalid for execution pub is_query: bool, } @@ -279,21 +282,21 @@ pub struct BroadcastedDeployAccountTransactionV1 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct BroadcastedDeployAccountTransactionV3 { /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// The salt for the address of the deployed contract - pub contract_address_salt: FieldElement, + pub contract_address_salt: Felt, /// The parameters passed to the constructor - pub constructor_calldata: Vec, + pub constructor_calldata: Vec, /// The hash of the deployed contract's class - pub class_hash: FieldElement, + pub class_hash: Felt, /// Resource bounds for the transaction execution pub resource_bounds: ResourceBoundsMapping, /// The tip for the transaction pub tip: u64, /// Data needed to allow the paymaster to pay for the transaction in native tokens - pub paymaster_data: Vec, + pub paymaster_data: Vec, /// The storage domain of the account's nonce (an account has a nonce per da mode) pub nonce_data_availability_mode: DataAvailabilityMode, /// The storage domain of the account's balance from which fee will be charged @@ -308,16 +311,16 @@ pub struct BroadcastedDeployAccountTransactionV3 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct BroadcastedInvokeTransactionV1 { /// Sender address - pub sender_address: FieldElement, + pub sender_address: Felt, /// The data expected by the account's `execute` function (in most usecases, this includes the /// called contract address and a function selector) - pub calldata: Vec, + pub calldata: Vec, /// The maximal fee that can be charged for including the transaction - pub max_fee: FieldElement, + pub max_fee: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// If set to `true`, uses a query-only transaction version that's invalid for execution pub is_query: bool, } @@ -328,22 +331,22 @@ pub struct BroadcastedInvokeTransactionV1 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct BroadcastedInvokeTransactionV3 { /// Sender address - pub sender_address: FieldElement, + pub sender_address: Felt, /// The data expected by the account's `execute` function (in most usecases, this includes the /// called contract address and a function selector) - pub calldata: Vec, + pub calldata: Vec, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// Resource bounds for the transaction execution pub resource_bounds: ResourceBoundsMapping, /// The tip for the transaction pub tip: u64, /// Data needed to allow the paymaster to pay for the transaction in native tokens - pub paymaster_data: Vec, + pub paymaster_data: Vec, /// Data needed to deploy the account contract from which this tx will be initiated - pub account_deployment_data: Vec, + pub account_deployment_data: Vec, /// The storage domain of the account's nonce (an account has a nonce per da mode) pub nonce_data_availability_mode: DataAvailabilityMode, /// The storage domain of the account's balance from which fee will be charged @@ -430,7 +433,7 @@ pub struct ContractErrorData { pub struct ContractStorageDiffItem { /// The contract address for which the storage changed #[serde_as(as = "UfeHex")] - pub address: FieldElement, + pub address: Felt, /// The changes in the storage of the contract pub storage_entries: Vec, } @@ -469,7 +472,7 @@ pub struct DataResources { #[derive(Debug, Clone, PartialEq, Eq)] pub struct DeclareTransactionReceipt { /// The hash identifying the transaction - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The fee that was charged by the sequencer pub actual_fee: FeePayment, /// Finality status of the tx @@ -500,15 +503,15 @@ pub struct DeclareTransactionTrace { #[derive(Debug, Clone, PartialEq, Eq)] pub struct DeclareTransactionV0 { /// Transaction hash - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The address of the account contract sending the declaration transaction - pub sender_address: FieldElement, + pub sender_address: Felt, /// The maximal fee that can be charged for including the transaction - pub max_fee: FieldElement, + pub max_fee: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// The hash of the declared class - pub class_hash: FieldElement, + pub class_hash: Felt, } /// Declare contract transaction v1. @@ -517,17 +520,17 @@ pub struct DeclareTransactionV0 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct DeclareTransactionV1 { /// Transaction hash - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The address of the account contract sending the declaration transaction - pub sender_address: FieldElement, + pub sender_address: Felt, /// The maximal fee that can be charged for including the transaction - pub max_fee: FieldElement, + pub max_fee: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// The hash of the declared class - pub class_hash: FieldElement, + pub class_hash: Felt, } /// Declare transaction v2. @@ -536,19 +539,19 @@ pub struct DeclareTransactionV1 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct DeclareTransactionV2 { /// Transaction hash - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The address of the account contract sending the declaration transaction - pub sender_address: FieldElement, + pub sender_address: Felt, /// The hash of the cairo assembly resulting from the sierra compilation - pub compiled_class_hash: FieldElement, + pub compiled_class_hash: Felt, /// The maximal fee that can be charged for including the transaction - pub max_fee: FieldElement, + pub max_fee: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// The hash of the declared class - pub class_hash: FieldElement, + pub class_hash: Felt, } /// Declare transaction v3. @@ -557,25 +560,25 @@ pub struct DeclareTransactionV2 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct DeclareTransactionV3 { /// Transaction hash - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The address of the account contract sending the declaration transaction - pub sender_address: FieldElement, + pub sender_address: Felt, /// The hash of the cairo assembly resulting from the sierra compilation - pub compiled_class_hash: FieldElement, + pub compiled_class_hash: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// The hash of the declared class - pub class_hash: FieldElement, + pub class_hash: Felt, /// Resource bounds for the transaction execution pub resource_bounds: ResourceBoundsMapping, /// The tip for the transaction pub tip: u64, /// Data needed to allow the paymaster to pay for the transaction in native tokens - pub paymaster_data: Vec, + pub paymaster_data: Vec, /// Data needed to deploy the account contract from which this tx will be initiated - pub account_deployment_data: Vec, + pub account_deployment_data: Vec, /// The storage domain of the account's nonce (an account has a nonce per da mode) pub nonce_data_availability_mode: DataAvailabilityMode, /// The storage domain of the account's balance from which fee will be charged @@ -591,17 +594,17 @@ pub struct DeclareTransactionV3 { pub struct DeclaredClassItem { /// The hash of the declared class #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, /// The cairo assembly hash corresponding to the declared class #[serde_as(as = "UfeHex")] - pub compiled_class_hash: FieldElement, + pub compiled_class_hash: Felt, } /// Deploy account transaction receipt. #[derive(Debug, Clone, PartialEq, Eq)] pub struct DeployAccountTransactionReceipt { /// The hash identifying the transaction - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The fee that was charged by the sequencer pub actual_fee: FeePayment, /// Finality status of the tx @@ -614,7 +617,7 @@ pub struct DeployAccountTransactionReceipt { pub execution_resources: ExecutionResources, pub execution_result: ExecutionResult, /// The address of the deployed contract - pub contract_address: FieldElement, + pub contract_address: Felt, } /// The execution trace of a deploy account transaction. @@ -637,19 +640,19 @@ pub struct DeployAccountTransactionTrace { #[derive(Debug, Clone, PartialEq, Eq)] pub struct DeployAccountTransactionV1 { /// Transaction hash - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The maximal fee that can be charged for including the transaction - pub max_fee: FieldElement, + pub max_fee: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// The salt for the address of the deployed contract - pub contract_address_salt: FieldElement, + pub contract_address_salt: Felt, /// The parameters passed to the constructor - pub constructor_calldata: Vec, + pub constructor_calldata: Vec, /// The hash of the deployed contract's class - pub class_hash: FieldElement, + pub class_hash: Felt, } /// Deploy account transaction. @@ -658,23 +661,23 @@ pub struct DeployAccountTransactionV1 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct DeployAccountTransactionV3 { /// Transaction hash - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// The salt for the address of the deployed contract - pub contract_address_salt: FieldElement, + pub contract_address_salt: Felt, /// The parameters passed to the constructor - pub constructor_calldata: Vec, + pub constructor_calldata: Vec, /// The hash of the deployed contract's class - pub class_hash: FieldElement, + pub class_hash: Felt, /// Resource bounds for the transaction execution pub resource_bounds: ResourceBoundsMapping, /// The tip for the transaction pub tip: u64, /// Data needed to allow the paymaster to pay for the transaction in native tokens - pub paymaster_data: Vec, + pub paymaster_data: Vec, /// The storage domain of the account's nonce (an account has a nonce per da mode) pub nonce_data_availability_mode: DataAvailabilityMode, /// The storage domain of the account's balance from which fee will be charged @@ -688,22 +691,22 @@ pub struct DeployAccountTransactionV3 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct DeployTransaction { /// Transaction hash - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// Version of the transaction scheme - pub version: FieldElement, + pub version: Felt, /// The salt for the address of the deployed contract - pub contract_address_salt: FieldElement, + pub contract_address_salt: Felt, /// The parameters passed to the constructor - pub constructor_calldata: Vec, + pub constructor_calldata: Vec, /// The hash of the deployed contract's class - pub class_hash: FieldElement, + pub class_hash: Felt, } /// Deploy transaction receipt. #[derive(Debug, Clone, PartialEq, Eq)] pub struct DeployTransactionReceipt { /// The hash identifying the transaction - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The fee that was charged by the sequencer pub actual_fee: FeePayment, /// Finality status of the tx @@ -716,7 +719,7 @@ pub struct DeployTransactionReceipt { pub execution_resources: ExecutionResources, pub execution_result: ExecutionResult, /// The address of the deployed contract - pub contract_address: FieldElement, + pub contract_address: Felt, } /// Deployed contract item. @@ -726,10 +729,10 @@ pub struct DeployTransactionReceipt { pub struct DeployedContractItem { /// The address of the contract #[serde_as(as = "UfeHex")] - pub address: FieldElement, + pub address: Felt, /// The hash of the contract code #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, } /// Emitted event. @@ -742,23 +745,23 @@ pub struct DeployedContractItem { pub struct EmittedEvent { /// From address #[serde_as(as = "UfeHex")] - pub from_address: FieldElement, + pub from_address: Felt, /// Keys #[serde_as(as = "Vec")] - pub keys: Vec, + pub keys: Vec, /// Data #[serde_as(as = "Vec")] - pub data: Vec, + pub data: Vec, /// The hash of the block in which the event was emitted #[serde(skip_serializing_if = "Option::is_none")] #[serde_as(as = "Option")] - pub block_hash: Option, + pub block_hash: Option, /// The number of the block in which the event was emitted #[serde(skip_serializing_if = "Option::is_none")] pub block_number: Option, /// The transaction that emitted the event #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] @@ -795,13 +798,13 @@ pub struct EntryPointsByType { pub struct Event { /// From address #[serde_as(as = "UfeHex")] - pub from_address: FieldElement, + pub from_address: Felt, /// Keys #[serde_as(as = "Vec")] - pub keys: Vec, + pub keys: Vec, /// Data #[serde_as(as = "Vec")] - pub data: Vec, + pub data: Vec, } /// Event filter. @@ -820,11 +823,11 @@ pub struct EventFilter { /// From contract #[serde(skip_serializing_if = "Option::is_none")] #[serde_as(as = "Option")] - pub address: Option, + pub address: Option, /// The values used to filter the events #[serde(skip_serializing_if = "Option::is_none")] #[serde_as(as = "Option>>")] - pub keys: Option>>, + pub keys: Option>>, } /// Events request. @@ -868,22 +871,22 @@ pub struct ExecutionResources { pub struct FeeEstimate { /// The Ethereum gas consumption of the transaction #[serde_as(as = "UfeHex")] - pub gas_consumed: FieldElement, + pub gas_consumed: Felt, /// The gas price (in wei or fri, depending on the tx version) that was used in the cost /// estimation #[serde_as(as = "UfeHex")] - pub gas_price: FieldElement, + pub gas_price: Felt, /// The Ethereum data gas consumption of the transaction #[serde_as(as = "UfeHex")] - pub data_gas_consumed: FieldElement, + pub data_gas_consumed: Felt, /// The data gas price (in wei or fri, depending on the tx version) that was used in the cost /// estimation #[serde_as(as = "UfeHex")] - pub data_gas_price: FieldElement, + pub data_gas_price: Felt, /// The estimated fee for the transaction (in wei or fri, depending on the tx version), equals /// to gas_consumed*gas_price + data_gas_consumed*data_gas_price #[serde_as(as = "UfeHex")] - pub overall_fee: FieldElement, + pub overall_fee: Felt, /// Units in which the fee is given pub unit: PriceUnit, } @@ -897,7 +900,7 @@ pub struct FeeEstimate { pub struct FeePayment { /// Amount paid #[serde_as(as = "UfeHex")] - pub amount: FieldElement, + pub amount: Felt, /// Units in which the fee is given pub unit: PriceUnit, } @@ -909,7 +912,7 @@ pub struct FeePayment { pub struct FlattenedSierraClass { /// The list of sierra instructions of which the program consists #[serde_as(as = "Vec")] - pub sierra_program: Vec, + pub sierra_program: Vec, /// The version of the contract class object. Currently, the Starknet os supports version 0.1.0 pub contract_class_version: String, /// Entry points by type @@ -927,13 +930,13 @@ pub struct FlattenedSierraClass { pub struct FunctionCall { /// Contract address #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, /// Entry point selector #[serde_as(as = "UfeHex")] - pub entry_point_selector: FieldElement, + pub entry_point_selector: Felt, /// The parameters passed to the function #[serde_as(as = "Vec")] - pub calldata: Vec, + pub calldata: Vec, } #[serde_as] @@ -942,24 +945,24 @@ pub struct FunctionCall { pub struct FunctionInvocation { /// Contract address #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, /// Entry point selector #[serde_as(as = "UfeHex")] - pub entry_point_selector: FieldElement, + pub entry_point_selector: Felt, /// The parameters passed to the function #[serde_as(as = "Vec")] - pub calldata: Vec, + pub calldata: Vec, /// The address of the invoking contract. 0 for the root invocation #[serde_as(as = "UfeHex")] - pub caller_address: FieldElement, + pub caller_address: Felt, /// The hash of the class being called #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, pub entry_point_type: EntryPointType, pub call_type: CallType, /// The value returned from the function invocation #[serde_as(as = "Vec")] - pub result: Vec, + pub result: Vec, /// The calls made by this invocation pub calls: Vec, /// The events emitted in this invocation @@ -982,7 +985,7 @@ pub enum FunctionStateMutability { #[derive(Debug, Clone, PartialEq, Eq)] pub struct InvokeTransactionReceipt { /// The hash identifying the transaction - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The fee that was charged by the sequencer pub actual_fee: FeePayment, /// Finality status of the tx @@ -1014,17 +1017,17 @@ pub struct InvokeTransactionTrace { #[derive(Debug, Clone, PartialEq, Eq)] pub struct InvokeTransactionV0 { /// Transaction hash - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The maximal fee that can be charged for including the transaction - pub max_fee: FieldElement, + pub max_fee: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// Contract address - pub contract_address: FieldElement, + pub contract_address: Felt, /// Entry point selector - pub entry_point_selector: FieldElement, + pub entry_point_selector: Felt, /// The parameters passed to the function - pub calldata: Vec, + pub calldata: Vec, } /// Invoke transaction v1. @@ -1033,18 +1036,18 @@ pub struct InvokeTransactionV0 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct InvokeTransactionV1 { /// Transaction hash - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// Sender address - pub sender_address: FieldElement, + pub sender_address: Felt, /// The data expected by the account's `execute` function (in most usecases, this includes the /// called contract address and a function selector) - pub calldata: Vec, + pub calldata: Vec, /// The maximal fee that can be charged for including the transaction - pub max_fee: FieldElement, + pub max_fee: Felt, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, } /// Invoke transaction v3. @@ -1053,24 +1056,24 @@ pub struct InvokeTransactionV1 { #[derive(Debug, Clone, PartialEq, Eq)] pub struct InvokeTransactionV3 { /// Transaction hash - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// Sender address - pub sender_address: FieldElement, + pub sender_address: Felt, /// The data expected by the account's `execute` function (in most usecases, this includes the /// called contract address and a function selector) - pub calldata: Vec, + pub calldata: Vec, /// Signature - pub signature: Vec, + pub signature: Vec, /// Nonce - pub nonce: FieldElement, + pub nonce: Felt, /// Resource bounds for the transaction execution pub resource_bounds: ResourceBoundsMapping, /// The tip for the transaction pub tip: u64, /// Data needed to allow the paymaster to pay for the transaction in native tokens - pub paymaster_data: Vec, + pub paymaster_data: Vec, /// Data needed to deploy the account contract from which this tx will be initiated - pub account_deployment_data: Vec, + pub account_deployment_data: Vec, /// The storage domain of the account's nonce (an account has a nonce per da mode) pub nonce_data_availability_mode: DataAvailabilityMode, /// The storage domain of the account's balance from which fee will be charged @@ -1090,18 +1093,18 @@ pub enum L1DataAvailabilityMode { #[derive(Debug, Clone, PartialEq, Eq)] pub struct L1HandlerTransaction { /// Transaction hash - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// Version of the transaction scheme - pub version: FieldElement, + pub version: Felt, /// The L1->L2 message nonce field of the sn core L1 contract at the time the transaction was /// sent pub nonce: u64, /// Contract address - pub contract_address: FieldElement, + pub contract_address: Felt, /// Entry point selector - pub entry_point_selector: FieldElement, + pub entry_point_selector: Felt, /// The parameters passed to the function - pub calldata: Vec, + pub calldata: Vec, } /// L1 handler transaction receipt. @@ -1112,7 +1115,7 @@ pub struct L1HandlerTransactionReceipt { /// The message hash as it appears on the L1 core contract pub message_hash: Hash256, /// The hash identifying the transaction - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The fee that was charged by the sequencer pub actual_fee: FeePayment, /// Finality status of the tx @@ -1148,7 +1151,7 @@ pub struct LegacyContractEntryPoint { pub offset: u64, /// A unique identifier of the entry point (function) in the program #[serde_as(as = "UfeHex")] - pub selector: FieldElement, + pub selector: Felt, } /// Deprecated entry points by type. @@ -1268,13 +1271,13 @@ pub struct MsgFromL1 { pub from_address: EthAddress, /// The target L2 address the message is sent to #[serde_as(as = "UfeHex")] - pub to_address: FieldElement, + pub to_address: Felt, /// The selector of the l1_handler in invoke in the target contract #[serde_as(as = "UfeHex")] - pub entry_point_selector: FieldElement, + pub entry_point_selector: Felt, /// The payload of the message #[serde_as(as = "Vec")] - pub payload: Vec, + pub payload: Vec, } /// Message to L1. @@ -1284,13 +1287,13 @@ pub struct MsgFromL1 { pub struct MsgToL1 { /// The address of the L2 contract sending the message #[serde_as(as = "UfeHex")] - pub from_address: FieldElement, + pub from_address: Felt, /// The target L1 address the message is sent to #[serde_as(as = "UfeHex")] - pub to_address: FieldElement, + pub to_address: Felt, /// The payload of the message #[serde_as(as = "Vec")] - pub payload: Vec, + pub payload: Vec, } /// Extra information on why trace is not available. Either it wasn't executed yet (received), or @@ -1310,10 +1313,10 @@ pub struct NoTraceAvailableErrorData { pub struct NonceUpdate { /// The address of the contract #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, /// The nonce for the given address at the end of the block #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, } /// Orderedevent. @@ -1327,10 +1330,10 @@ pub struct OrderedEvent { pub order: u64, /// Keys #[serde_as(as = "Vec")] - pub keys: Vec, + pub keys: Vec, /// Data #[serde_as(as = "Vec")] - pub data: Vec, + pub data: Vec, } /// Orderedmessage. @@ -1344,13 +1347,13 @@ pub struct OrderedMessage { pub order: u64, /// The address of the L2 contract sending the message #[serde_as(as = "UfeHex")] - pub from_address: FieldElement, + pub from_address: Felt, /// The target L1 address the message is sent to #[serde_as(as = "UfeHex")] - pub to_address: FieldElement, + pub to_address: Felt, /// The payload of the message #[serde_as(as = "Vec")] - pub payload: Vec, + pub payload: Vec, } /// Pending block with transactions and receipts. @@ -1365,12 +1368,12 @@ pub struct PendingBlockWithReceipts { pub transactions: Vec, /// The hash of this block's parent #[serde_as(as = "UfeHex")] - pub parent_hash: FieldElement, + pub parent_hash: Felt, /// The time in which the block was created, encoded in Unix time pub timestamp: u64, /// The Starknet identity of the sequencer submitting this block #[serde_as(as = "UfeHex")] - pub sequencer_address: FieldElement, + pub sequencer_address: Felt, /// The price of L1 gas in the block pub l1_gas_price: ResourcePrice, /// The price of L1 data gas in the block @@ -1391,15 +1394,15 @@ pub struct PendingBlockWithReceipts { pub struct PendingBlockWithTxHashes { /// The hashes of the transactions included in this block #[serde_as(as = "Vec")] - pub transactions: Vec, + pub transactions: Vec, /// The hash of this block's parent #[serde_as(as = "UfeHex")] - pub parent_hash: FieldElement, + pub parent_hash: Felt, /// The time in which the block was created, encoded in Unix time pub timestamp: u64, /// The Starknet identity of the sequencer submitting this block #[serde_as(as = "UfeHex")] - pub sequencer_address: FieldElement, + pub sequencer_address: Felt, /// The price of L1 gas in the block pub l1_gas_price: ResourcePrice, /// The price of L1 data gas in the block @@ -1422,12 +1425,12 @@ pub struct PendingBlockWithTxs { pub transactions: Vec, /// The hash of this block's parent #[serde_as(as = "UfeHex")] - pub parent_hash: FieldElement, + pub parent_hash: Felt, /// The time in which the block was created, encoded in Unix time pub timestamp: u64, /// The Starknet identity of the sequencer submitting this block #[serde_as(as = "UfeHex")] - pub sequencer_address: FieldElement, + pub sequencer_address: Felt, /// The price of L1 gas in the block pub l1_gas_price: ResourcePrice, /// The price of L1 data gas in the block @@ -1447,7 +1450,7 @@ pub struct PendingBlockWithTxs { pub struct PendingStateUpdate { /// The previous global state root #[serde_as(as = "UfeHex")] - pub old_root: FieldElement, + pub old_root: Felt, /// State diff pub state_diff: StateDiff, } @@ -1470,10 +1473,10 @@ pub enum PriceUnit { pub struct ReplacedClassItem { /// The address of the contract whose class was replaced #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, /// The new class hash #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, } #[serde_as] @@ -1503,10 +1506,10 @@ pub struct ResourceBoundsMapping { pub struct ResourcePrice { /// The price of one unit of the given resource, denominated in fri (10^-18 strk) #[serde_as(as = "UfeHex")] - pub price_in_fri: FieldElement, + pub price_in_fri: Felt, /// The price of one unit of the given resource, denominated in wei #[serde_as(as = "UfeHex")] - pub price_in_wei: FieldElement, + pub price_in_wei: Felt, } /// Result page request. @@ -1551,7 +1554,7 @@ pub enum SequencerTransactionStatus { pub struct SierraEntryPoint { /// A unique identifier of the entry point (function) in the program #[serde_as(as = "UfeHex")] - pub selector: FieldElement, + pub selector: Felt, /// The index of the function in the program pub function_idx: u64, } @@ -1721,7 +1724,7 @@ pub struct StateDiff { pub storage_diffs: Vec, /// Deprecated declared classes #[serde_as(as = "Vec")] - pub deprecated_declared_classes: Vec, + pub deprecated_declared_classes: Vec, /// Declared classes pub declared_classes: Vec, /// Deployed contracts @@ -1739,13 +1742,13 @@ pub struct StateDiff { pub struct StateUpdate { /// Block hash #[serde_as(as = "UfeHex")] - pub block_hash: FieldElement, + pub block_hash: Felt, /// The previous global state root #[serde_as(as = "UfeHex")] - pub old_root: FieldElement, + pub old_root: Felt, /// The new global state root #[serde_as(as = "UfeHex")] - pub new_root: FieldElement, + pub new_root: Felt, /// State diff pub state_diff: StateDiff, } @@ -1757,10 +1760,10 @@ pub struct StateUpdate { pub struct StorageEntry { /// The key of the changed value #[serde_as(as = "UfeHex")] - pub key: FieldElement, + pub key: Felt, /// The new value applied to the given address #[serde_as(as = "UfeHex")] - pub value: FieldElement, + pub value: Felt, } /// Sync status. @@ -1772,17 +1775,17 @@ pub struct StorageEntry { pub struct SyncStatus { /// The hash of the block from which the sync started #[serde_as(as = "UfeHex")] - pub starting_block_hash: FieldElement, + pub starting_block_hash: Felt, /// The number (height) of the block from which the sync started pub starting_block_num: u64, /// The hash of the current block being synchronized #[serde_as(as = "UfeHex")] - pub current_block_hash: FieldElement, + pub current_block_hash: Felt, /// The number (height) of the current block being synchronized pub current_block_num: u64, /// The hash of the estimated highest block to be synchronized #[serde_as(as = "UfeHex")] - pub highest_block_hash: FieldElement, + pub highest_block_hash: Felt, /// The number (height) of the estimated highest block to be synchronized pub highest_block_num: u64, } @@ -1834,7 +1837,7 @@ pub struct TransactionReceiptWithBlockInfo { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct TransactionTraceWithHash { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub trace_root: TransactionTrace, } @@ -2009,14 +2012,14 @@ pub struct GetClassAtRequest { /// The hash of the requested block, or number (height) of the requested block, or a block tag pub block_id: BlockId, /// The address of the contract whose class definition will be returned - pub contract_address: FieldElement, + pub contract_address: Felt, } /// Reference version of [GetClassAtRequest]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetClassAtRequestRef<'a> { pub block_id: &'a BlockId, - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } /// Request for method starknet_getClassHashAt @@ -2025,14 +2028,14 @@ pub struct GetClassHashAtRequest { /// The hash of the requested block, or number (height) of the requested block, or a block tag pub block_id: BlockId, /// The address of the contract whose class hash will be returned - pub contract_address: FieldElement, + pub contract_address: Felt, } /// Reference version of [GetClassHashAtRequest]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetClassHashAtRequestRef<'a> { pub block_id: &'a BlockId, - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } /// Request for method starknet_getClass @@ -2041,14 +2044,14 @@ pub struct GetClassRequest { /// The hash of the requested block, or number (height) of the requested block, or a block tag pub block_id: BlockId, /// The hash of the requested contract class - pub class_hash: FieldElement, + pub class_hash: Felt, } /// Reference version of [GetClassRequest]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetClassRequestRef<'a> { pub block_id: &'a BlockId, - pub class_hash: &'a FieldElement, + pub class_hash: &'a Felt, } /// Request for method starknet_getEvents @@ -2069,14 +2072,14 @@ pub struct GetNonceRequest { /// The hash of the requested block, or number (height) of the requested block, or a block tag pub block_id: BlockId, /// The address of the contract whose nonce we're seeking - pub contract_address: FieldElement, + pub contract_address: Felt, } /// Reference version of [GetNonceRequest]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetNonceRequestRef<'a> { pub block_id: &'a BlockId, - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } /// Request for method starknet_getStateUpdate @@ -2096,9 +2099,9 @@ pub struct GetStateUpdateRequestRef<'a> { #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetStorageAtRequest { /// The address of the contract to read from - pub contract_address: FieldElement, + pub contract_address: Felt, /// The key to the storage value for the given contract - pub key: FieldElement, + pub key: Felt, /// The hash of the requested block, or number (height) of the requested block, or a block tag pub block_id: BlockId, } @@ -2106,8 +2109,8 @@ pub struct GetStorageAtRequest { /// Reference version of [GetStorageAtRequest]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetStorageAtRequestRef<'a> { - pub contract_address: &'a FieldElement, - pub key: &'a FieldElement, + pub contract_address: &'a Felt, + pub key: &'a Felt, pub block_id: &'a BlockId, } @@ -2129,37 +2132,37 @@ pub struct GetTransactionByBlockIdAndIndexRequestRef<'a> { /// Request for method starknet_getTransactionByHash #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetTransactionByHashRequest { - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } /// Reference version of [GetTransactionByHashRequest]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetTransactionByHashRequestRef<'a> { - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, } /// Request for method starknet_getTransactionReceipt #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetTransactionReceiptRequest { - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } /// Reference version of [GetTransactionReceiptRequest]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetTransactionReceiptRequestRef<'a> { - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, } /// Request for method starknet_getTransactionStatus #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetTransactionStatusRequest { - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } /// Reference version of [GetTransactionStatusRequest]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct GetTransactionStatusRequestRef<'a> { - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, } /// Request for method starknet_simulateTransactions @@ -2206,13 +2209,13 @@ pub struct TraceBlockTransactionsRequestRef<'a> { /// Request for method starknet_traceTransaction #[derive(Debug, Clone, PartialEq, Eq)] pub struct TraceTransactionRequest { - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } /// Reference version of [TraceTransactionRequest]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct TraceTransactionRequestRef<'a> { - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, } impl Serialize for BroadcastedDeclareTransactionV1 { @@ -2222,24 +2225,24 @@ impl Serialize for BroadcastedDeclareTransactionV1 { struct Tagged<'a> { pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub sender_address: &'a FieldElement, + pub sender_address: &'a Felt, #[serde_as(as = "UfeHex")] - pub max_fee: &'a FieldElement, + pub max_fee: &'a Felt, #[serde_as(as = "UfeHex")] - pub version: &'a FieldElement, + pub version: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, pub contract_class: &'a CompressedLegacyContractClass, } let r#type = "DECLARE"; let version = &(if self.is_query { - FieldElement::ONE + QUERY_VERSION_OFFSET + Felt::ONE + QUERY_VERSION_OFFSET } else { - FieldElement::ONE + Felt::ONE }); let tagged = Tagged { @@ -2264,15 +2267,15 @@ impl<'de> Deserialize<'de> for BroadcastedDeclareTransactionV1 { struct Tagged { pub r#type: Option, #[serde_as(as = "UfeHex")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "UfeHex")] - pub max_fee: FieldElement, + pub max_fee: Felt, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, pub contract_class: CompressedLegacyContractClass, } @@ -2284,9 +2287,9 @@ impl<'de> Deserialize<'de> for BroadcastedDeclareTransactionV1 { } } - let is_query = if tagged.version == FieldElement::ONE { + let is_query = if tagged.version == Felt::ONE { false - } else if tagged.version == FieldElement::ONE + QUERY_VERSION_OFFSET { + } else if tagged.version == Felt::ONE + QUERY_VERSION_OFFSET { true } else { return Err(serde::de::Error::custom("invalid `version` value")); @@ -2310,26 +2313,26 @@ impl Serialize for BroadcastedDeclareTransactionV2 { struct Tagged<'a> { pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub sender_address: &'a FieldElement, + pub sender_address: &'a Felt, #[serde_as(as = "UfeHex")] - pub compiled_class_hash: &'a FieldElement, + pub compiled_class_hash: &'a Felt, #[serde_as(as = "UfeHex")] - pub max_fee: &'a FieldElement, + pub max_fee: &'a Felt, #[serde_as(as = "UfeHex")] - pub version: &'a FieldElement, + pub version: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, pub contract_class: &'a FlattenedSierraClass, } let r#type = "DECLARE"; let version = &(if self.is_query { - FieldElement::TWO + QUERY_VERSION_OFFSET + Felt::TWO + QUERY_VERSION_OFFSET } else { - FieldElement::TWO + Felt::TWO }); let tagged = Tagged { @@ -2355,17 +2358,17 @@ impl<'de> Deserialize<'de> for BroadcastedDeclareTransactionV2 { struct Tagged { pub r#type: Option, #[serde_as(as = "UfeHex")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "UfeHex")] - pub compiled_class_hash: FieldElement, + pub compiled_class_hash: Felt, #[serde_as(as = "UfeHex")] - pub max_fee: FieldElement, + pub max_fee: Felt, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, pub contract_class: FlattenedSierraClass, } @@ -2377,9 +2380,9 @@ impl<'de> Deserialize<'de> for BroadcastedDeclareTransactionV2 { } } - let is_query = if tagged.version == FieldElement::TWO { + let is_query = if tagged.version == Felt::TWO { false - } else if tagged.version == FieldElement::TWO + QUERY_VERSION_OFFSET { + } else if tagged.version == Felt::TWO + QUERY_VERSION_OFFSET { true } else { return Err(serde::de::Error::custom("invalid `version` value")); @@ -2404,23 +2407,23 @@ impl Serialize for BroadcastedDeclareTransactionV3 { struct Tagged<'a> { pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub sender_address: &'a FieldElement, + pub sender_address: &'a Felt, #[serde_as(as = "UfeHex")] - pub compiled_class_hash: &'a FieldElement, + pub compiled_class_hash: &'a Felt, #[serde_as(as = "UfeHex")] - pub version: &'a FieldElement, + pub version: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, pub contract_class: &'a FlattenedSierraClass, pub resource_bounds: &'a ResourceBoundsMapping, #[serde_as(as = "NumAsHex")] pub tip: &'a u64, #[serde_as(as = "[UfeHex]")] - pub paymaster_data: &'a [FieldElement], + pub paymaster_data: &'a [Felt], #[serde_as(as = "[UfeHex]")] - pub account_deployment_data: &'a [FieldElement], + pub account_deployment_data: &'a [Felt], pub nonce_data_availability_mode: &'a DataAvailabilityMode, pub fee_data_availability_mode: &'a DataAvailabilityMode, } @@ -2428,9 +2431,9 @@ impl Serialize for BroadcastedDeclareTransactionV3 { let r#type = "DECLARE"; let version = &(if self.is_query { - FieldElement::THREE + QUERY_VERSION_OFFSET + Felt::THREE + QUERY_VERSION_OFFSET } else { - FieldElement::THREE + Felt::THREE }); let tagged = Tagged { @@ -2461,23 +2464,23 @@ impl<'de> Deserialize<'de> for BroadcastedDeclareTransactionV3 { struct Tagged { pub r#type: Option, #[serde_as(as = "UfeHex")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "UfeHex")] - pub compiled_class_hash: FieldElement, + pub compiled_class_hash: Felt, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, pub contract_class: FlattenedSierraClass, pub resource_bounds: ResourceBoundsMapping, #[serde_as(as = "NumAsHex")] pub tip: u64, #[serde_as(as = "Vec")] - pub paymaster_data: Vec, + pub paymaster_data: Vec, #[serde_as(as = "Vec")] - pub account_deployment_data: Vec, + pub account_deployment_data: Vec, pub nonce_data_availability_mode: DataAvailabilityMode, pub fee_data_availability_mode: DataAvailabilityMode, } @@ -2490,9 +2493,9 @@ impl<'de> Deserialize<'de> for BroadcastedDeclareTransactionV3 { } } - let is_query = if tagged.version == FieldElement::THREE { + let is_query = if tagged.version == Felt::THREE { false - } else if tagged.version == FieldElement::THREE + QUERY_VERSION_OFFSET { + } else if tagged.version == Felt::THREE + QUERY_VERSION_OFFSET { true } else { return Err(serde::de::Error::custom("invalid `version` value")); @@ -2522,27 +2525,27 @@ impl Serialize for BroadcastedDeployAccountTransactionV1 { struct Tagged<'a> { pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub max_fee: &'a FieldElement, + pub max_fee: &'a Felt, #[serde_as(as = "UfeHex")] - pub version: &'a FieldElement, + pub version: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, #[serde_as(as = "UfeHex")] - pub contract_address_salt: &'a FieldElement, + pub contract_address_salt: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub constructor_calldata: &'a [FieldElement], + pub constructor_calldata: &'a [Felt], #[serde_as(as = "UfeHex")] - pub class_hash: &'a FieldElement, + pub class_hash: &'a Felt, } let r#type = "DEPLOY_ACCOUNT"; let version = &(if self.is_query { - FieldElement::ONE + QUERY_VERSION_OFFSET + Felt::ONE + QUERY_VERSION_OFFSET } else { - FieldElement::ONE + Felt::ONE }); let tagged = Tagged { @@ -2568,19 +2571,19 @@ impl<'de> Deserialize<'de> for BroadcastedDeployAccountTransactionV1 { struct Tagged { pub r#type: Option, #[serde_as(as = "UfeHex")] - pub max_fee: FieldElement, + pub max_fee: Felt, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, #[serde_as(as = "UfeHex")] - pub contract_address_salt: FieldElement, + pub contract_address_salt: Felt, #[serde_as(as = "Vec")] - pub constructor_calldata: Vec, + pub constructor_calldata: Vec, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, } let tagged = Tagged::deserialize(deserializer)?; @@ -2591,9 +2594,9 @@ impl<'de> Deserialize<'de> for BroadcastedDeployAccountTransactionV1 { } } - let is_query = if tagged.version == FieldElement::ONE { + let is_query = if tagged.version == Felt::ONE { false - } else if tagged.version == FieldElement::ONE + QUERY_VERSION_OFFSET { + } else if tagged.version == Felt::ONE + QUERY_VERSION_OFFSET { true } else { return Err(serde::de::Error::custom("invalid `version` value")); @@ -2618,22 +2621,22 @@ impl Serialize for BroadcastedDeployAccountTransactionV3 { struct Tagged<'a> { pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub version: &'a FieldElement, + pub version: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, #[serde_as(as = "UfeHex")] - pub contract_address_salt: &'a FieldElement, + pub contract_address_salt: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub constructor_calldata: &'a [FieldElement], + pub constructor_calldata: &'a [Felt], #[serde_as(as = "UfeHex")] - pub class_hash: &'a FieldElement, + pub class_hash: &'a Felt, pub resource_bounds: &'a ResourceBoundsMapping, #[serde_as(as = "NumAsHex")] pub tip: &'a u64, #[serde_as(as = "[UfeHex]")] - pub paymaster_data: &'a [FieldElement], + pub paymaster_data: &'a [Felt], pub nonce_data_availability_mode: &'a DataAvailabilityMode, pub fee_data_availability_mode: &'a DataAvailabilityMode, } @@ -2641,9 +2644,9 @@ impl Serialize for BroadcastedDeployAccountTransactionV3 { let r#type = "DEPLOY_ACCOUNT"; let version = &(if self.is_query { - FieldElement::THREE + QUERY_VERSION_OFFSET + Felt::THREE + QUERY_VERSION_OFFSET } else { - FieldElement::THREE + Felt::THREE }); let tagged = Tagged { @@ -2673,22 +2676,22 @@ impl<'de> Deserialize<'de> for BroadcastedDeployAccountTransactionV3 { struct Tagged { pub r#type: Option, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, #[serde_as(as = "UfeHex")] - pub contract_address_salt: FieldElement, + pub contract_address_salt: Felt, #[serde_as(as = "Vec")] - pub constructor_calldata: Vec, + pub constructor_calldata: Vec, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, pub resource_bounds: ResourceBoundsMapping, #[serde_as(as = "NumAsHex")] pub tip: u64, #[serde_as(as = "Vec")] - pub paymaster_data: Vec, + pub paymaster_data: Vec, pub nonce_data_availability_mode: DataAvailabilityMode, pub fee_data_availability_mode: DataAvailabilityMode, } @@ -2701,9 +2704,9 @@ impl<'de> Deserialize<'de> for BroadcastedDeployAccountTransactionV3 { } } - let is_query = if tagged.version == FieldElement::THREE { + let is_query = if tagged.version == Felt::THREE { false - } else if tagged.version == FieldElement::THREE + QUERY_VERSION_OFFSET { + } else if tagged.version == Felt::THREE + QUERY_VERSION_OFFSET { true } else { return Err(serde::de::Error::custom("invalid `version` value")); @@ -2732,25 +2735,25 @@ impl Serialize for BroadcastedInvokeTransactionV1 { struct Tagged<'a> { pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub sender_address: &'a FieldElement, + pub sender_address: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub calldata: &'a [FieldElement], + pub calldata: &'a [Felt], #[serde_as(as = "UfeHex")] - pub max_fee: &'a FieldElement, + pub max_fee: &'a Felt, #[serde_as(as = "UfeHex")] - pub version: &'a FieldElement, + pub version: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, } let r#type = "INVOKE"; let version = &(if self.is_query { - FieldElement::ONE + QUERY_VERSION_OFFSET + Felt::ONE + QUERY_VERSION_OFFSET } else { - FieldElement::ONE + Felt::ONE }); let tagged = Tagged { @@ -2775,17 +2778,17 @@ impl<'de> Deserialize<'de> for BroadcastedInvokeTransactionV1 { struct Tagged { pub r#type: Option, #[serde_as(as = "UfeHex")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "Vec")] - pub calldata: Vec, + pub calldata: Vec, #[serde_as(as = "UfeHex")] - pub max_fee: FieldElement, + pub max_fee: Felt, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, } let tagged = Tagged::deserialize(deserializer)?; @@ -2796,9 +2799,9 @@ impl<'de> Deserialize<'de> for BroadcastedInvokeTransactionV1 { } } - let is_query = if tagged.version == FieldElement::ONE { + let is_query = if tagged.version == Felt::ONE { false - } else if tagged.version == FieldElement::ONE + QUERY_VERSION_OFFSET { + } else if tagged.version == Felt::ONE + QUERY_VERSION_OFFSET { true } else { return Err(serde::de::Error::custom("invalid `version` value")); @@ -2822,22 +2825,22 @@ impl Serialize for BroadcastedInvokeTransactionV3 { struct Tagged<'a> { pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub sender_address: &'a FieldElement, + pub sender_address: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub calldata: &'a [FieldElement], + pub calldata: &'a [Felt], #[serde_as(as = "UfeHex")] - pub version: &'a FieldElement, + pub version: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, pub resource_bounds: &'a ResourceBoundsMapping, #[serde_as(as = "NumAsHex")] pub tip: &'a u64, #[serde_as(as = "[UfeHex]")] - pub paymaster_data: &'a [FieldElement], + pub paymaster_data: &'a [Felt], #[serde_as(as = "[UfeHex]")] - pub account_deployment_data: &'a [FieldElement], + pub account_deployment_data: &'a [Felt], pub nonce_data_availability_mode: &'a DataAvailabilityMode, pub fee_data_availability_mode: &'a DataAvailabilityMode, } @@ -2845,9 +2848,9 @@ impl Serialize for BroadcastedInvokeTransactionV3 { let r#type = "INVOKE"; let version = &(if self.is_query { - FieldElement::THREE + QUERY_VERSION_OFFSET + Felt::THREE + QUERY_VERSION_OFFSET } else { - FieldElement::THREE + Felt::THREE }); let tagged = Tagged { @@ -2877,22 +2880,22 @@ impl<'de> Deserialize<'de> for BroadcastedInvokeTransactionV3 { struct Tagged { pub r#type: Option, #[serde_as(as = "UfeHex")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "Vec")] - pub calldata: Vec, + pub calldata: Vec, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, pub resource_bounds: ResourceBoundsMapping, #[serde_as(as = "NumAsHex")] pub tip: u64, #[serde_as(as = "Vec")] - pub paymaster_data: Vec, + pub paymaster_data: Vec, #[serde_as(as = "Vec")] - pub account_deployment_data: Vec, + pub account_deployment_data: Vec, pub nonce_data_availability_mode: DataAvailabilityMode, pub fee_data_availability_mode: DataAvailabilityMode, } @@ -2905,9 +2908,9 @@ impl<'de> Deserialize<'de> for BroadcastedInvokeTransactionV3 { } } - let is_query = if tagged.version == FieldElement::THREE { + let is_query = if tagged.version == Felt::THREE { false - } else if tagged.version == FieldElement::THREE + QUERY_VERSION_OFFSET { + } else if tagged.version == Felt::THREE + QUERY_VERSION_OFFSET { true } else { return Err(serde::de::Error::custom("invalid `version` value")); @@ -2936,7 +2939,7 @@ impl Serialize for DeclareTransactionReceipt { struct Tagged<'a> { pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub actual_fee: &'a FeePayment, pub finality_status: &'a TransactionFinalityStatus, pub messages_sent: &'a [MsgToL1], @@ -2970,7 +2973,7 @@ impl<'de> Deserialize<'de> for DeclareTransactionReceipt { struct Tagged { pub r#type: Option, #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub actual_fee: FeePayment, pub finality_status: TransactionFinalityStatus, pub messages_sent: Vec, @@ -3066,18 +3069,18 @@ impl Serialize for DeclareTransactionV0 { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub sender_address: &'a FieldElement, + pub sender_address: &'a Felt, #[serde_as(as = "UfeHex")] - pub max_fee: &'a FieldElement, + pub max_fee: &'a Felt, #[serde_as(as = "NumAsHex")] pub version: &'a u64, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub class_hash: &'a FieldElement, + pub class_hash: &'a Felt, } let r#type = "DECLARE"; @@ -3105,18 +3108,18 @@ impl<'de> Deserialize<'de> for DeclareTransactionV0 { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub r#type: Option, #[serde_as(as = "UfeHex")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "UfeHex")] - pub max_fee: FieldElement, + pub max_fee: Felt, #[serde_as(as = "Option")] pub version: Option, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, } let tagged = Tagged::deserialize(deserializer)?; @@ -3149,20 +3152,20 @@ impl Serialize for DeclareTransactionV1 { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub sender_address: &'a FieldElement, + pub sender_address: &'a Felt, #[serde_as(as = "UfeHex")] - pub max_fee: &'a FieldElement, + pub max_fee: &'a Felt, #[serde_as(as = "NumAsHex")] pub version: &'a u64, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, #[serde_as(as = "UfeHex")] - pub class_hash: &'a FieldElement, + pub class_hash: &'a Felt, } let r#type = "DECLARE"; @@ -3191,20 +3194,20 @@ impl<'de> Deserialize<'de> for DeclareTransactionV1 { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub r#type: Option, #[serde_as(as = "UfeHex")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "UfeHex")] - pub max_fee: FieldElement, + pub max_fee: Felt, #[serde_as(as = "Option")] pub version: Option, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, } let tagged = Tagged::deserialize(deserializer)?; @@ -3238,22 +3241,22 @@ impl Serialize for DeclareTransactionV2 { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub sender_address: &'a FieldElement, + pub sender_address: &'a Felt, #[serde_as(as = "UfeHex")] - pub compiled_class_hash: &'a FieldElement, + pub compiled_class_hash: &'a Felt, #[serde_as(as = "UfeHex")] - pub max_fee: &'a FieldElement, + pub max_fee: &'a Felt, #[serde_as(as = "NumAsHex")] pub version: &'a u64, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, #[serde_as(as = "UfeHex")] - pub class_hash: &'a FieldElement, + pub class_hash: &'a Felt, } let r#type = "DECLARE"; @@ -3283,22 +3286,22 @@ impl<'de> Deserialize<'de> for DeclareTransactionV2 { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub r#type: Option, #[serde_as(as = "UfeHex")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "UfeHex")] - pub compiled_class_hash: FieldElement, + pub compiled_class_hash: Felt, #[serde_as(as = "UfeHex")] - pub max_fee: FieldElement, + pub max_fee: Felt, #[serde_as(as = "Option")] pub version: Option, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, } let tagged = Tagged::deserialize(deserializer)?; @@ -3333,27 +3336,27 @@ impl Serialize for DeclareTransactionV3 { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub sender_address: &'a FieldElement, + pub sender_address: &'a Felt, #[serde_as(as = "UfeHex")] - pub compiled_class_hash: &'a FieldElement, + pub compiled_class_hash: &'a Felt, #[serde_as(as = "NumAsHex")] pub version: &'a u64, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, #[serde_as(as = "UfeHex")] - pub class_hash: &'a FieldElement, + pub class_hash: &'a Felt, pub resource_bounds: &'a ResourceBoundsMapping, #[serde_as(as = "NumAsHex")] pub tip: &'a u64, #[serde_as(as = "[UfeHex]")] - pub paymaster_data: &'a [FieldElement], + pub paymaster_data: &'a [Felt], #[serde_as(as = "[UfeHex]")] - pub account_deployment_data: &'a [FieldElement], + pub account_deployment_data: &'a [Felt], pub nonce_data_availability_mode: &'a DataAvailabilityMode, pub fee_data_availability_mode: &'a DataAvailabilityMode, } @@ -3390,27 +3393,27 @@ impl<'de> Deserialize<'de> for DeclareTransactionV3 { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub r#type: Option, #[serde_as(as = "UfeHex")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "UfeHex")] - pub compiled_class_hash: FieldElement, + pub compiled_class_hash: Felt, #[serde_as(as = "Option")] pub version: Option, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, pub resource_bounds: ResourceBoundsMapping, #[serde_as(as = "NumAsHex")] pub tip: u64, #[serde_as(as = "Vec")] - pub paymaster_data: Vec, + pub paymaster_data: Vec, #[serde_as(as = "Vec")] - pub account_deployment_data: Vec, + pub account_deployment_data: Vec, pub nonce_data_availability_mode: DataAvailabilityMode, pub fee_data_availability_mode: DataAvailabilityMode, } @@ -3452,7 +3455,7 @@ impl Serialize for DeployAccountTransactionReceipt { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub actual_fee: &'a FeePayment, pub finality_status: &'a TransactionFinalityStatus, pub messages_sent: &'a [MsgToL1], @@ -3462,7 +3465,7 @@ impl Serialize for DeployAccountTransactionReceipt { pub execution_result: &'a ExecutionResult, pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } let r#type = "DEPLOY_ACCOUNT"; @@ -3489,7 +3492,7 @@ impl<'de> Deserialize<'de> for DeployAccountTransactionReceipt { #[derive(Deserialize)] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub actual_fee: FeePayment, pub finality_status: TransactionFinalityStatus, pub messages_sent: Vec, @@ -3499,7 +3502,7 @@ impl<'de> Deserialize<'de> for DeployAccountTransactionReceipt { pub execution_result: ExecutionResult, pub r#type: Option, #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, } let tagged = Tagged::deserialize(deserializer)?; @@ -3593,22 +3596,22 @@ impl Serialize for DeployAccountTransactionV1 { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub max_fee: &'a FieldElement, + pub max_fee: &'a Felt, #[serde_as(as = "NumAsHex")] pub version: &'a u64, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, #[serde_as(as = "UfeHex")] - pub contract_address_salt: &'a FieldElement, + pub contract_address_salt: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub constructor_calldata: &'a [FieldElement], + pub constructor_calldata: &'a [Felt], #[serde_as(as = "UfeHex")] - pub class_hash: &'a FieldElement, + pub class_hash: &'a Felt, } let r#type = "DEPLOY_ACCOUNT"; @@ -3638,22 +3641,22 @@ impl<'de> Deserialize<'de> for DeployAccountTransactionV1 { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub r#type: Option, #[serde_as(as = "UfeHex")] - pub max_fee: FieldElement, + pub max_fee: Felt, #[serde_as(as = "Option")] pub version: Option, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, #[serde_as(as = "UfeHex")] - pub contract_address_salt: FieldElement, + pub contract_address_salt: Felt, #[serde_as(as = "Vec")] - pub constructor_calldata: Vec, + pub constructor_calldata: Vec, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, } let tagged = Tagged::deserialize(deserializer)?; @@ -3688,25 +3691,25 @@ impl Serialize for DeployAccountTransactionV3 { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub r#type: &'a str, #[serde_as(as = "NumAsHex")] pub version: &'a u64, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, #[serde_as(as = "UfeHex")] - pub contract_address_salt: &'a FieldElement, + pub contract_address_salt: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub constructor_calldata: &'a [FieldElement], + pub constructor_calldata: &'a [Felt], #[serde_as(as = "UfeHex")] - pub class_hash: &'a FieldElement, + pub class_hash: &'a Felt, pub resource_bounds: &'a ResourceBoundsMapping, #[serde_as(as = "NumAsHex")] pub tip: &'a u64, #[serde_as(as = "[UfeHex]")] - pub paymaster_data: &'a [FieldElement], + pub paymaster_data: &'a [Felt], pub nonce_data_availability_mode: &'a DataAvailabilityMode, pub fee_data_availability_mode: &'a DataAvailabilityMode, } @@ -3742,25 +3745,25 @@ impl<'de> Deserialize<'de> for DeployAccountTransactionV3 { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub r#type: Option, #[serde_as(as = "Option")] pub version: Option, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, #[serde_as(as = "UfeHex")] - pub contract_address_salt: FieldElement, + pub contract_address_salt: Felt, #[serde_as(as = "Vec")] - pub constructor_calldata: Vec, + pub constructor_calldata: Vec, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, pub resource_bounds: ResourceBoundsMapping, #[serde_as(as = "NumAsHex")] pub tip: u64, #[serde_as(as = "Vec")] - pub paymaster_data: Vec, + pub paymaster_data: Vec, pub nonce_data_availability_mode: DataAvailabilityMode, pub fee_data_availability_mode: DataAvailabilityMode, } @@ -3801,16 +3804,16 @@ impl Serialize for DeployTransaction { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, #[serde_as(as = "UfeHex")] - pub version: &'a FieldElement, + pub version: &'a Felt, pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub contract_address_salt: &'a FieldElement, + pub contract_address_salt: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub constructor_calldata: &'a [FieldElement], + pub constructor_calldata: &'a [Felt], #[serde_as(as = "UfeHex")] - pub class_hash: &'a FieldElement, + pub class_hash: &'a Felt, } let r#type = "DEPLOY"; @@ -3835,16 +3838,16 @@ impl<'de> Deserialize<'de> for DeployTransaction { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, pub r#type: Option, #[serde_as(as = "UfeHex")] - pub contract_address_salt: FieldElement, + pub contract_address_salt: Felt, #[serde_as(as = "Vec")] - pub constructor_calldata: Vec, + pub constructor_calldata: Vec, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, } let tagged = Tagged::deserialize(deserializer)?; @@ -3871,7 +3874,7 @@ impl Serialize for DeployTransactionReceipt { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub actual_fee: &'a FeePayment, pub finality_status: &'a TransactionFinalityStatus, pub messages_sent: &'a [MsgToL1], @@ -3881,7 +3884,7 @@ impl Serialize for DeployTransactionReceipt { pub execution_result: &'a ExecutionResult, pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } let r#type = "DEPLOY"; @@ -3908,7 +3911,7 @@ impl<'de> Deserialize<'de> for DeployTransactionReceipt { #[derive(Deserialize)] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub actual_fee: FeePayment, pub finality_status: TransactionFinalityStatus, pub messages_sent: Vec, @@ -3918,7 +3921,7 @@ impl<'de> Deserialize<'de> for DeployTransactionReceipt { pub execution_result: ExecutionResult, pub r#type: Option, #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, } let tagged = Tagged::deserialize(deserializer)?; @@ -3949,7 +3952,7 @@ impl Serialize for InvokeTransactionReceipt { struct Tagged<'a> { pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub actual_fee: &'a FeePayment, pub finality_status: &'a TransactionFinalityStatus, pub messages_sent: &'a [MsgToL1], @@ -3983,7 +3986,7 @@ impl<'de> Deserialize<'de> for InvokeTransactionReceipt { struct Tagged { pub r#type: Option, #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub actual_fee: FeePayment, pub finality_status: TransactionFinalityStatus, pub messages_sent: Vec, @@ -4083,20 +4086,20 @@ impl Serialize for InvokeTransactionV0 { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub max_fee: &'a FieldElement, + pub max_fee: &'a Felt, #[serde_as(as = "NumAsHex")] pub version: &'a u64, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, #[serde_as(as = "UfeHex")] - pub entry_point_selector: &'a FieldElement, + pub entry_point_selector: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub calldata: &'a [FieldElement], + pub calldata: &'a [Felt], } let r#type = "INVOKE"; @@ -4125,20 +4128,20 @@ impl<'de> Deserialize<'de> for InvokeTransactionV0 { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub r#type: Option, #[serde_as(as = "UfeHex")] - pub max_fee: FieldElement, + pub max_fee: Felt, #[serde_as(as = "Option")] pub version: Option, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, #[serde_as(as = "UfeHex")] - pub entry_point_selector: FieldElement, + pub entry_point_selector: Felt, #[serde_as(as = "Vec")] - pub calldata: Vec, + pub calldata: Vec, } let tagged = Tagged::deserialize(deserializer)?; @@ -4172,20 +4175,20 @@ impl Serialize for InvokeTransactionV1 { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub sender_address: &'a FieldElement, + pub sender_address: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub calldata: &'a [FieldElement], + pub calldata: &'a [Felt], #[serde_as(as = "UfeHex")] - pub max_fee: &'a FieldElement, + pub max_fee: &'a Felt, #[serde_as(as = "NumAsHex")] pub version: &'a u64, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, } let r#type = "INVOKE"; @@ -4214,20 +4217,20 @@ impl<'de> Deserialize<'de> for InvokeTransactionV1 { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub r#type: Option, #[serde_as(as = "UfeHex")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "Vec")] - pub calldata: Vec, + pub calldata: Vec, #[serde_as(as = "UfeHex")] - pub max_fee: FieldElement, + pub max_fee: Felt, #[serde_as(as = "Option")] pub version: Option, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, } let tagged = Tagged::deserialize(deserializer)?; @@ -4261,25 +4264,25 @@ impl Serialize for InvokeTransactionV3 { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub r#type: &'a str, #[serde_as(as = "UfeHex")] - pub sender_address: &'a FieldElement, + pub sender_address: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub calldata: &'a [FieldElement], + pub calldata: &'a [Felt], #[serde_as(as = "NumAsHex")] pub version: &'a u64, #[serde_as(as = "[UfeHex]")] - pub signature: &'a [FieldElement], + pub signature: &'a [Felt], #[serde_as(as = "UfeHex")] - pub nonce: &'a FieldElement, + pub nonce: &'a Felt, pub resource_bounds: &'a ResourceBoundsMapping, #[serde_as(as = "NumAsHex")] pub tip: &'a u64, #[serde_as(as = "[UfeHex]")] - pub paymaster_data: &'a [FieldElement], + pub paymaster_data: &'a [Felt], #[serde_as(as = "[UfeHex]")] - pub account_deployment_data: &'a [FieldElement], + pub account_deployment_data: &'a [Felt], pub nonce_data_availability_mode: &'a DataAvailabilityMode, pub fee_data_availability_mode: &'a DataAvailabilityMode, } @@ -4315,25 +4318,25 @@ impl<'de> Deserialize<'de> for InvokeTransactionV3 { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub r#type: Option, #[serde_as(as = "UfeHex")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "Vec")] - pub calldata: Vec, + pub calldata: Vec, #[serde_as(as = "Option")] pub version: Option, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, pub resource_bounds: ResourceBoundsMapping, #[serde_as(as = "NumAsHex")] pub tip: u64, #[serde_as(as = "Vec")] - pub paymaster_data: Vec, + pub paymaster_data: Vec, #[serde_as(as = "Vec")] - pub account_deployment_data: Vec, + pub account_deployment_data: Vec, pub nonce_data_availability_mode: DataAvailabilityMode, pub fee_data_availability_mode: DataAvailabilityMode, } @@ -4374,18 +4377,18 @@ impl Serialize for L1HandlerTransaction { #[derive(Serialize)] struct Tagged<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, #[serde_as(as = "UfeHex")] - pub version: &'a FieldElement, + pub version: &'a Felt, pub r#type: &'a str, #[serde_as(as = "NumAsHex")] pub nonce: &'a u64, #[serde_as(as = "UfeHex")] - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, #[serde_as(as = "UfeHex")] - pub entry_point_selector: &'a FieldElement, + pub entry_point_selector: &'a Felt, #[serde_as(as = "[UfeHex]")] - pub calldata: &'a [FieldElement], + pub calldata: &'a [Felt], } let r#type = "L1_HANDLER"; @@ -4411,18 +4414,18 @@ impl<'de> Deserialize<'de> for L1HandlerTransaction { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct Tagged { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, pub r#type: Option, #[serde_as(as = "NumAsHex")] pub nonce: u64, #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, #[serde_as(as = "UfeHex")] - pub entry_point_selector: FieldElement, + pub entry_point_selector: Felt, #[serde_as(as = "Vec")] - pub calldata: Vec, + pub calldata: Vec, } let tagged = Tagged::deserialize(deserializer)?; @@ -4452,7 +4455,7 @@ impl Serialize for L1HandlerTransactionReceipt { pub r#type: &'a str, pub message_hash: &'a Hash256, #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, pub actual_fee: &'a FeePayment, pub finality_status: &'a TransactionFinalityStatus, pub messages_sent: &'a [MsgToL1], @@ -4488,7 +4491,7 @@ impl<'de> Deserialize<'de> for L1HandlerTransactionReceipt { pub r#type: Option, pub message_hash: Hash256, #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub actual_fee: FeePayment, pub finality_status: TransactionFinalityStatus, pub messages_sent: Vec, @@ -5543,7 +5546,7 @@ impl Serialize for GetClassAtRequest { #[serde(transparent)] struct Field1<'a> { #[serde_as(as = "UfeHex")] - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } use serde::ser::SerializeSeq; @@ -5574,7 +5577,7 @@ impl<'a> Serialize for GetClassAtRequestRef<'a> { #[serde(transparent)] struct Field1<'a> { #[serde_as(as = "UfeHex")] - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } use serde::ser::SerializeSeq; @@ -5599,7 +5602,7 @@ impl<'de> Deserialize<'de> for GetClassAtRequest { struct AsObject { pub block_id: BlockId, #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, } #[derive(Deserialize)] @@ -5613,7 +5616,7 @@ impl<'de> Deserialize<'de> for GetClassAtRequest { #[serde(transparent)] struct Field1 { #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, } let temp = serde_json::Value::deserialize(deserializer)?; @@ -5660,7 +5663,7 @@ impl Serialize for GetClassHashAtRequest { #[serde(transparent)] struct Field1<'a> { #[serde_as(as = "UfeHex")] - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } use serde::ser::SerializeSeq; @@ -5691,7 +5694,7 @@ impl<'a> Serialize for GetClassHashAtRequestRef<'a> { #[serde(transparent)] struct Field1<'a> { #[serde_as(as = "UfeHex")] - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } use serde::ser::SerializeSeq; @@ -5716,7 +5719,7 @@ impl<'de> Deserialize<'de> for GetClassHashAtRequest { struct AsObject { pub block_id: BlockId, #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, } #[derive(Deserialize)] @@ -5730,7 +5733,7 @@ impl<'de> Deserialize<'de> for GetClassHashAtRequest { #[serde(transparent)] struct Field1 { #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, } let temp = serde_json::Value::deserialize(deserializer)?; @@ -5777,7 +5780,7 @@ impl Serialize for GetClassRequest { #[serde(transparent)] struct Field1<'a> { #[serde_as(as = "UfeHex")] - pub class_hash: &'a FieldElement, + pub class_hash: &'a Felt, } use serde::ser::SerializeSeq; @@ -5808,7 +5811,7 @@ impl<'a> Serialize for GetClassRequestRef<'a> { #[serde(transparent)] struct Field1<'a> { #[serde_as(as = "UfeHex")] - pub class_hash: &'a FieldElement, + pub class_hash: &'a Felt, } use serde::ser::SerializeSeq; @@ -5833,7 +5836,7 @@ impl<'de> Deserialize<'de> for GetClassRequest { struct AsObject { pub block_id: BlockId, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, } #[derive(Deserialize)] @@ -5847,7 +5850,7 @@ impl<'de> Deserialize<'de> for GetClassRequest { #[serde(transparent)] struct Field1 { #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, } let temp = serde_json::Value::deserialize(deserializer)?; @@ -5971,7 +5974,7 @@ impl Serialize for GetNonceRequest { #[serde(transparent)] struct Field1<'a> { #[serde_as(as = "UfeHex")] - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } use serde::ser::SerializeSeq; @@ -6002,7 +6005,7 @@ impl<'a> Serialize for GetNonceRequestRef<'a> { #[serde(transparent)] struct Field1<'a> { #[serde_as(as = "UfeHex")] - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } use serde::ser::SerializeSeq; @@ -6027,7 +6030,7 @@ impl<'de> Deserialize<'de> for GetNonceRequest { struct AsObject { pub block_id: BlockId, #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, } #[derive(Deserialize)] @@ -6041,7 +6044,7 @@ impl<'de> Deserialize<'de> for GetNonceRequest { #[serde(transparent)] struct Field1 { #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, } let temp = serde_json::Value::deserialize(deserializer)?; @@ -6159,7 +6162,7 @@ impl Serialize for GetStorageAtRequest { #[serde(transparent)] struct Field0<'a> { #[serde_as(as = "UfeHex")] - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } #[serde_as] @@ -6167,7 +6170,7 @@ impl Serialize for GetStorageAtRequest { #[serde(transparent)] struct Field1<'a> { #[serde_as(as = "UfeHex")] - pub key: &'a FieldElement, + pub key: &'a Felt, } #[derive(Serialize)] @@ -6199,7 +6202,7 @@ impl<'a> Serialize for GetStorageAtRequestRef<'a> { #[serde(transparent)] struct Field0<'a> { #[serde_as(as = "UfeHex")] - pub contract_address: &'a FieldElement, + pub contract_address: &'a Felt, } #[serde_as] @@ -6207,7 +6210,7 @@ impl<'a> Serialize for GetStorageAtRequestRef<'a> { #[serde(transparent)] struct Field1<'a> { #[serde_as(as = "UfeHex")] - pub key: &'a FieldElement, + pub key: &'a Felt, } #[derive(Serialize)] @@ -6238,9 +6241,9 @@ impl<'de> Deserialize<'de> for GetStorageAtRequest { #[derive(Deserialize)] struct AsObject { #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, #[serde_as(as = "UfeHex")] - pub key: FieldElement, + pub key: Felt, pub block_id: BlockId, } @@ -6249,7 +6252,7 @@ impl<'de> Deserialize<'de> for GetStorageAtRequest { #[serde(transparent)] struct Field0 { #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, } #[serde_as] @@ -6257,7 +6260,7 @@ impl<'de> Deserialize<'de> for GetStorageAtRequest { #[serde(transparent)] struct Field1 { #[serde_as(as = "UfeHex")] - pub key: FieldElement, + pub key: Felt, } #[derive(Deserialize)] @@ -6418,7 +6421,7 @@ impl Serialize for GetTransactionByHashRequest { #[serde(transparent)] struct Field0<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, } use serde::ser::SerializeSeq; @@ -6440,7 +6443,7 @@ impl<'a> Serialize for GetTransactionByHashRequestRef<'a> { #[serde(transparent)] struct Field0<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, } use serde::ser::SerializeSeq; @@ -6461,7 +6464,7 @@ impl<'de> Deserialize<'de> for GetTransactionByHashRequest { #[derive(Deserialize)] struct AsObject { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } #[serde_as] @@ -6469,7 +6472,7 @@ impl<'de> Deserialize<'de> for GetTransactionByHashRequest { #[serde(transparent)] struct Field0 { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } let temp = serde_json::Value::deserialize(deserializer)?; @@ -6502,7 +6505,7 @@ impl Serialize for GetTransactionReceiptRequest { #[serde(transparent)] struct Field0<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, } use serde::ser::SerializeSeq; @@ -6524,7 +6527,7 @@ impl<'a> Serialize for GetTransactionReceiptRequestRef<'a> { #[serde(transparent)] struct Field0<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, } use serde::ser::SerializeSeq; @@ -6545,7 +6548,7 @@ impl<'de> Deserialize<'de> for GetTransactionReceiptRequest { #[derive(Deserialize)] struct AsObject { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } #[serde_as] @@ -6553,7 +6556,7 @@ impl<'de> Deserialize<'de> for GetTransactionReceiptRequest { #[serde(transparent)] struct Field0 { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } let temp = serde_json::Value::deserialize(deserializer)?; @@ -6586,7 +6589,7 @@ impl Serialize for GetTransactionStatusRequest { #[serde(transparent)] struct Field0<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, } use serde::ser::SerializeSeq; @@ -6608,7 +6611,7 @@ impl<'a> Serialize for GetTransactionStatusRequestRef<'a> { #[serde(transparent)] struct Field0<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, } use serde::ser::SerializeSeq; @@ -6629,7 +6632,7 @@ impl<'de> Deserialize<'de> for GetTransactionStatusRequest { #[derive(Deserialize)] struct AsObject { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } #[serde_as] @@ -6637,7 +6640,7 @@ impl<'de> Deserialize<'de> for GetTransactionStatusRequest { #[serde(transparent)] struct Field0 { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } let temp = serde_json::Value::deserialize(deserializer)?; @@ -6928,7 +6931,7 @@ impl Serialize for TraceTransactionRequest { #[serde(transparent)] struct Field0<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, } use serde::ser::SerializeSeq; @@ -6950,7 +6953,7 @@ impl<'a> Serialize for TraceTransactionRequestRef<'a> { #[serde(transparent)] struct Field0<'a> { #[serde_as(as = "UfeHex")] - pub transaction_hash: &'a FieldElement, + pub transaction_hash: &'a Felt, } use serde::ser::SerializeSeq; @@ -6971,7 +6974,7 @@ impl<'de> Deserialize<'de> for TraceTransactionRequest { #[derive(Deserialize)] struct AsObject { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } #[serde_as] @@ -6979,7 +6982,7 @@ impl<'de> Deserialize<'de> for TraceTransactionRequest { #[serde(transparent)] struct Field0 { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } let temp = serde_json::Value::deserialize(deserializer)?; diff --git a/starknet-core/src/types/contract/legacy.rs b/starknet-core/src/types/contract/legacy.rs index 6b3eb797..3803a218 100644 --- a/starknet-core/src/types/contract/legacy.rs +++ b/starknet-core/src/types/contract/legacy.rs @@ -5,7 +5,7 @@ use crate::{ serde::{num_hex::u64 as u64_hex, unsigned_field_element::UfeHex}, types::{ contract::{ComputeClassHashError, JsonError}, - FieldElement, FunctionStateMutability, LegacyContractAbiEntry, LegacyContractEntryPoint, + Felt, FunctionStateMutability, LegacyContractAbiEntry, LegacyContractEntryPoint, LegacyEntryPointsByType, LegacyEventAbiEntry, LegacyEventAbiType, LegacyFunctionAbiEntry, LegacyFunctionAbiType, LegacyStructAbiEntry, LegacyStructAbiType, LegacyStructMember, LegacyTypedParameter, @@ -24,7 +24,7 @@ use crate::types::{contract::CompressProgramError, CompressedLegacyContractClass #[cfg(feature = "std")] use flate2::{write::GzEncoder, Compression}; -const API_VERSION: FieldElement = FieldElement::ZERO; +const API_VERSION: Felt = Felt::ZERO; #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] @@ -55,12 +55,12 @@ pub struct LegacyProgram { #[serde(skip_serializing_if = "Option::is_none")] pub compiler_version: Option, #[serde_as(as = "Vec")] - pub data: Vec, + pub data: Vec, pub debug_info: Option, pub hints: BTreeMap>, pub identifiers: BTreeMap, pub main_scope: String, - // Impossible to use [FieldElement] here as by definition field elements are smaller + // Impossible to use [Felt] here as by definition field elements are smaller // than prime pub prime: String, pub reference_manager: LegacyReferenceManager, @@ -72,7 +72,7 @@ pub struct LegacyProgram { pub struct RawLegacyEntryPoint { pub offset: LegacyEntrypointOffset, #[serde_as(as = "UfeHex")] - pub selector: FieldElement, + pub selector: Felt, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -280,17 +280,19 @@ struct AttributeForHintedHash; impl From for u64 { fn from(value: LegacyEntrypointOffset) -> Self { match value { - LegacyEntrypointOffset::U64AsHex(inner) => inner, - LegacyEntrypointOffset::U64AsInt(inner) => inner, + LegacyEntrypointOffset::U64AsHex(inner) | LegacyEntrypointOffset::U64AsInt(inner) => { + inner + } } } } -impl From for FieldElement { +impl From for Felt { fn from(value: LegacyEntrypointOffset) -> Self { match value { - LegacyEntrypointOffset::U64AsHex(inner) => inner.into(), - LegacyEntrypointOffset::U64AsInt(inner) => inner.into(), + LegacyEntrypointOffset::U64AsHex(inner) | LegacyEntrypointOffset::U64AsInt(inner) => { + inner.into() + } } } } @@ -359,26 +361,26 @@ impl<'de> Deserialize<'de> for RawLegacyAbiEntry { let temp_value = serde_json::Value::deserialize(deserializer)?; match &temp_value["type"] { serde_json::Value::String(type_str) => match &type_str[..] { - "constructor" => Ok(RawLegacyAbiEntry::Constructor( + "constructor" => Ok(Self::Constructor( RawLegacyConstructor::deserialize(temp_value).map_err(|err| { DeError::custom(format!("invalid constructor variant: {err}")) })?, )), - "function" => Ok(RawLegacyAbiEntry::Function( + "function" => Ok(Self::Function( RawLegacyFunction::deserialize(temp_value).map_err(|err| { DeError::custom(format!("invalid function variant: {err}")) })?, )), - "struct" => Ok(RawLegacyAbiEntry::Struct( + "struct" => Ok(Self::Struct( RawLegacyStruct::deserialize(temp_value) .map_err(|err| DeError::custom(format!("invalid struct variant: {err}")))?, )), - "l1_handler" => Ok(RawLegacyAbiEntry::L1Handler( + "l1_handler" => Ok(Self::L1Handler( RawLegacyL1Handler::deserialize(temp_value).map_err(|err| { DeError::custom(format!("invalid l1_handler variant: {err}")) })?, )), - "event" => Ok(RawLegacyAbiEntry::Event( + "event" => Ok(Self::Event( RawLegacyEvent::deserialize(temp_value) .map_err(|err| DeError::custom(format!("invalid event variant: {err}")))?, )), @@ -392,7 +394,7 @@ impl<'de> Deserialize<'de> for RawLegacyAbiEntry { } impl LegacyContractClass { - pub fn class_hash(&self) -> Result { + pub fn class_hash(&self) -> Result { let mut elements = Vec::new(); elements.push(API_VERSION); @@ -400,7 +402,7 @@ impl LegacyContractClass { // Hashes external entry points elements.push({ let mut buffer = Vec::new(); - for entrypoint in self.entry_points_by_type.external.iter() { + for entrypoint in &self.entry_points_by_type.external { buffer.push(entrypoint.selector); buffer.push(entrypoint.offset.into()); } @@ -410,7 +412,7 @@ impl LegacyContractClass { // Hashes L1 handler entry points elements.push({ let mut buffer = Vec::new(); - for entrypoint in self.entry_points_by_type.l1_handler.iter() { + for entrypoint in &self.entry_points_by_type.l1_handler { buffer.push(entrypoint.selector); buffer.push(entrypoint.offset.into()); } @@ -420,7 +422,7 @@ impl LegacyContractClass { // Hashes constructor entry points elements.push({ let mut buffer = Vec::new(); - for entrypoint in self.entry_points_by_type.constructor.iter() { + for entrypoint in &self.entry_points_by_type.constructor { buffer.push(entrypoint.selector); buffer.push(entrypoint.offset.into()); } @@ -447,7 +449,7 @@ impl LegacyContractClass { Ok(compute_hash_on_elements(&elements)) } - pub fn hinted_class_hash(&self) -> Result { + pub fn hinted_class_hash(&self) -> Result { #[serde_as] #[derive(Serialize)] struct ContractArtifactForHash<'a> { @@ -499,10 +501,8 @@ impl LegacyProgram { #[serde(skip_serializing_if = "Option::is_none")] compiler_version: &'a Option, #[serde_as(as = "Vec")] - data: &'a Vec, - // Needed due to pathfinder bug: - // https://github.com/eqlabs/pathfinder/issues/1371 - debug_info: EmptyDebugInfo, + data: &'a Vec, + debug_info: Option<()>, hints: &'a BTreeMap>, identifiers: &'a BTreeMap, main_scope: &'a String, @@ -510,24 +510,12 @@ impl LegacyProgram { reference_manager: &'a LegacyReferenceManager, } - #[derive(Serialize)] - pub struct EmptyDebugInfo { - file_contents: Unit, - instruction_locations: Unit, - } - - #[derive(Serialize)] - pub struct Unit {} - let program_json = serde_json::to_string(&ProgramWithoutDebugInfo { attributes: &self.attributes, builtins: &self.builtins, compiler_version: &self.compiler_version, data: &self.data, - debug_info: EmptyDebugInfo { - file_contents: Unit {}, - instruction_locations: Unit {}, - }, + debug_info: None, hints: &self.hints, identifiers: &self.identifiers, main_scope: &self.main_scope, @@ -609,7 +597,7 @@ impl SerializeAs for ProgramForHintedHash { #[serde(skip_serializing_if = "Option::is_none")] compiler_version: &'a Option, #[serde_as(as = "Vec")] - data: &'a Vec, + data: &'a Vec, debug_info: &'a Option, hints: &'a BTreeMap>, identifiers: &'a BTreeMap, @@ -865,9 +853,7 @@ mod tests { include_str!( "../../../test-data/contracts/cairo0/artifacts/pre-0.11.0/event_example.txt" ), - ] - .into_iter() - { + ] { serde_json::from_str::(raw_artifact).unwrap(); } } @@ -905,13 +891,12 @@ mod tests { ), ), ] - .into_iter() { let artifact = serde_json::from_str::(raw_artifact).unwrap(); let computed_hash = artifact.class_hash().unwrap(); let hashes: ContractHashes = serde_json::from_str(raw_hashes).unwrap(); - let expected_hash = FieldElement::from_hex_be(&hashes.class_hash).unwrap(); + let expected_hash = Felt::from_hex(&hashes.class_hash).unwrap(); assert_eq!(computed_hash, expected_hash); } @@ -950,13 +935,12 @@ mod tests { ), ), ] - .into_iter() { let artifact = serde_json::from_str::(raw_artifact).unwrap(); let computed_hash = artifact.hinted_class_hash().unwrap(); let hashes: ContractHashes = serde_json::from_str(raw_hashes).unwrap(); - let expected_hash = FieldElement::from_hex_be(&hashes.hinted_class_hash).unwrap(); + let expected_hash = Felt::from_hex(&hashes.hinted_class_hash).unwrap(); assert_eq!(computed_hash, expected_hash); } diff --git a/starknet-core/src/types/contract/mod.rs b/starknet-core/src/types/contract/mod.rs index 6772ef92..ba1b17ba 100644 --- a/starknet-core/src/types/contract/mod.rs +++ b/starknet-core/src/types/contract/mod.rs @@ -7,7 +7,7 @@ use starknet_crypto::{poseidon_hash_many, PoseidonHasher}; use crate::{ serde::unsigned_field_element::UfeHex, - types::{EntryPointsByType, FieldElement, FlattenedSierraClass, SierraEntryPoint}, + types::{EntryPointsByType, Felt, FlattenedSierraClass, SierraEntryPoint}, utils::{ cairo_short_string_to_felt, normalize_address, starknet_keccak, CairoShortStringToFeltError, }, @@ -16,20 +16,20 @@ use crate::{ /// Module containing types related to artifacts of contracts compiled with a Cairo 0.x compiler. pub mod legacy; -/// Cairo string for "CONTRACT_CLASS_V0.1.0" -const PREFIX_CONTRACT_CLASS_V0_1_0: FieldElement = FieldElement::from_mont([ - 5800711240972404213, - 15539482671244488427, - 18446734822722598327, +/// Cairo string for `CONTRACT_CLASS_V0.1.0` +const PREFIX_CONTRACT_CLASS_V0_1_0: Felt = Felt::from_raw([ 37302452645455172, + 18446734822722598327, + 15539482671244488427, + 5800711240972404213, ]); -/// Cairo string for "COMPILED_CLASS_V1" -const PREFIX_COMPILED_CLASS_V1: FieldElement = FieldElement::from_mont([ - 2291010424822318237, - 1609463842841646376, - 18446744073709549462, +/// Cairo string for `COMPILED_CLASS_V1` +const PREFIX_COMPILED_CLASS_V1: Felt = Felt::from_raw([ 324306817650036332, + 18446744073709549462, + 1609463842841646376, + 2291010424822318237, ]); #[derive(Debug, Clone, Serialize)] @@ -46,7 +46,7 @@ pub enum ContractArtifact { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct SierraClass { #[serde_as(as = "Vec")] - pub sierra_program: Vec, + pub sierra_program: Vec, pub sierra_program_debug_info: SierraClassDebugInfo, pub contract_class_version: String, pub entry_points_by_type: EntryPointsByType, @@ -60,7 +60,7 @@ pub struct CompiledClass { pub prime: String, pub compiler_version: String, #[serde_as(as = "Vec")] - pub bytecode: Vec, + pub bytecode: Vec, /// Represents the structure of the bytecode segments, using a nested list of segment lengths. /// For example, [2, [3, 4]] represents a bytecode with 2 segments, the first is a leaf of /// length 2 and the second is a node with 2 children of lengths 3 and 4. @@ -121,7 +121,7 @@ pub struct PythonicHint { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct CompiledClassEntrypoint { #[serde_as(as = "UfeHex")] - pub selector: FieldElement, + pub selector: Felt, pub offset: u64, pub builtins: Vec, } @@ -265,7 +265,7 @@ enum BytecodeSegmentStructure { /// Represents a leaf in the bytecode segment tree. struct BytecodeLeaf { // NOTE: change this to a slice? - data: Vec, + data: Vec, } /// Internal structure used for post-Sierra-1.5.0 CASM hash calculation. @@ -278,7 +278,7 @@ struct BytecodeSegmentedNode { /// Internal structure used for post-Sierra-1.5.0 CASM hash calculation. /// -/// Represents a child of [BytecodeSegmentedNode]. +/// Represents a child of [`BytecodeSegmentedNode`]. struct BytecodeSegment { segment_length: u64, #[allow(unused)] @@ -410,7 +410,7 @@ pub use errors::{ pub use errors::CompressProgramError; impl SierraClass { - pub fn class_hash(&self) -> Result { + pub fn class_hash(&self) -> Result { // Technically we don't have to use the Pythonic JSON style here. Doing this just to align // with the official `cairo-lang` CLI. // @@ -457,7 +457,7 @@ impl SierraClass { } impl FlattenedSierraClass { - pub fn class_hash(&self) -> FieldElement { + pub fn class_hash(&self) -> Felt { let mut hasher = PoseidonHasher::new(); hasher.update(PREFIX_CONTRACT_CLASS_V0_1_0); @@ -481,7 +481,7 @@ impl FlattenedSierraClass { } impl CompiledClass { - pub fn class_hash(&self) -> Result { + pub fn class_hash(&self) -> Result { let mut hasher = PoseidonHasher::new(); hasher.update(PREFIX_COMPILED_CLASS_V1); @@ -542,15 +542,15 @@ impl CompiledClass { fn hash_entrypoints( entrypoints: &[CompiledClassEntrypoint], - ) -> Result { + ) -> Result { let mut hasher = PoseidonHasher::new(); - for entry in entrypoints.iter() { + for entry in entrypoints { hasher.update(entry.selector); hasher.update(entry.offset.into()); let mut builtin_hasher = PoseidonHasher::new(); - for builtin in entry.builtins.iter() { + for builtin in &entry.builtins { builtin_hasher.update(cairo_short_string_to_felt(builtin)?) } @@ -565,7 +565,7 @@ impl CompiledClass { // `visited_pcs` should be given in reverse order, and is consumed by the function. Returns the // BytecodeSegmentStructure and the total length of the processed segment. fn create_bytecode_segment_structure_inner( - bytecode: &[FieldElement], + bytecode: &[Felt], bytecode_segment_lengths: &IntOrList, visited_pcs: &mut Vec, bytecode_offset: &mut u64, @@ -594,7 +594,7 @@ impl CompiledClass { let mut res = Vec::new(); let mut total_len = 0; - for item in bytecode_segment_lengths.iter() { + for item in bytecode_segment_lengths { let visited_pc_before = if !visited_pcs.is_empty() { Some(visited_pcs[visited_pcs.len() - 1]) } else { @@ -649,7 +649,7 @@ impl CompiledClass { } impl BytecodeSegmentStructure { - fn hash(&self) -> FieldElement { + fn hash(&self) -> Felt { match self { Self::BytecodeLeaf(inner) => inner.hash(), Self::BytecodeSegmentedNode(inner) => inner.hash(), @@ -658,19 +658,19 @@ impl BytecodeSegmentStructure { } impl BytecodeLeaf { - fn hash(&self) -> FieldElement { + fn hash(&self) -> Felt { poseidon_hash_many(&self.data) } } impl BytecodeSegmentedNode { - fn hash(&self) -> FieldElement { + fn hash(&self) -> Felt { let mut hasher = PoseidonHasher::new(); - for node in self.segments.iter() { + for node in &self.segments { hasher.update(node.segment_length.into()); hasher.update(node.inner_structure.hash()); } - hasher.finalize() + FieldElement::ONE + hasher.finalize() + Felt::ONE } } @@ -761,7 +761,7 @@ impl Serialize for TypedAbiEvent { } match self { - TypedAbiEvent::Struct(inner) => StructRef::serialize( + Self::Struct(inner) => StructRef::serialize( &StructRef { name: &inner.name, kind: "struct", @@ -769,7 +769,7 @@ impl Serialize for TypedAbiEvent { }, serializer, ), - TypedAbiEvent::Enum(inner) => EnumRef::serialize( + Self::Enum(inner) => EnumRef::serialize( &EnumRef { name: &inner.name, kind: "enum", @@ -790,7 +790,7 @@ impl Serialize for IntOrList { Self::Int(int) => serializer.serialize_u64(*int), Self::List(list) => { let mut seq = serializer.serialize_seq(Some(list.len()))?; - for item in list.iter() { + for item in list { seq.serialize_element(item)?; } seq.end() @@ -802,7 +802,7 @@ impl Serialize for IntOrList { impl<'de> Visitor<'de> for IntOrListVisitor { type Value = IntOrList; - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(formatter, "number or list") } @@ -834,10 +834,10 @@ impl<'de> Deserialize<'de> for IntOrList { } } -fn hash_sierra_entrypoints(entrypoints: &[SierraEntryPoint]) -> FieldElement { +fn hash_sierra_entrypoints(entrypoints: &[SierraEntryPoint]) -> Felt { let mut hasher = PoseidonHasher::new(); - for entry in entrypoints.iter() { + for entry in entrypoints { hasher.update(entry.selector); hasher.update(entry.function_idx.into()); } @@ -864,9 +864,7 @@ mod tests { include_str!("../../../test-data/contracts/cairo2/artifacts/abi_types_sierra.txt"), include_str!("../../../test-data/contracts/cairo2/artifacts/erc20_sierra.txt"), include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_sierra.txt"), - ] - .into_iter() - { + ] { match serde_json::from_str::(raw_artifact) { Ok(ContractArtifact::SierraClass(_)) => {} _ => panic!("Unexpected result"), @@ -883,9 +881,7 @@ mod tests { include_str!("../../../test-data/contracts/cairo2/artifacts/abi_types_compiled.txt"), include_str!("../../../test-data/contracts/cairo2/artifacts/erc20_compiled.txt"), include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_compiled.txt"), - ] - .into_iter() - { + ] { match serde_json::from_str::(raw_artifact) { Ok(ContractArtifact::CompiledClass(_)) => {} _ => panic!("Unexpected result"), @@ -924,14 +920,12 @@ mod tests { include_str!("../../../test-data/contracts/cairo2/artifacts/abi_types_sierra.txt"), include_str!("../../../test-data/contracts/cairo2/artifacts/abi_types.hashes.json"), ), - ] - .into_iter() - { + ] { let sierra_class = serde_json::from_str::(raw_artifact).unwrap(); let computed_hash = sierra_class.class_hash().unwrap(); let hashes: ContractHashes = serde_json::from_str(raw_hashes).unwrap(); - let expected_hash = FieldElement::from_hex_be(&hashes.sierra_class_hash).unwrap(); + let expected_hash = Felt::from_hex(&hashes.sierra_class_hash).unwrap(); assert_eq!(computed_hash, expected_hash); } @@ -965,14 +959,12 @@ mod tests { include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20_compiled.txt"), include_str!("../../../test-data/contracts/cairo2.6/artifacts/erc20.hashes.json"), ), - ] - .into_iter() - { + ] { let compiled_class = serde_json::from_str::(raw_artifact).unwrap(); let computed_hash = compiled_class.class_hash().unwrap(); let hashes: ContractHashes = serde_json::from_str(raw_hashes).unwrap(); - let expected_hash = FieldElement::from_hex_be(&hashes.compiled_class_hash).unwrap(); + let expected_hash = Felt::from_hex(&hashes.compiled_class_hash).unwrap(); assert_eq!(computed_hash, expected_hash); } diff --git a/starknet-core/src/types/conversions.rs b/starknet-core/src/types/conversions.rs index 38e7aa5f..a4a9ba1d 100644 --- a/starknet-core/src/types/conversions.rs +++ b/starknet-core/src/types/conversions.rs @@ -10,33 +10,29 @@ impl From for RawLegacyAbiEntry { fn from(value: LegacyContractAbiEntry) -> Self { match value { LegacyContractAbiEntry::Function(inner) => match inner.r#type { - LegacyFunctionAbiType::Function => RawLegacyAbiEntry::Function(RawLegacyFunction { + LegacyFunctionAbiType::Function => Self::Function(RawLegacyFunction { inputs: inner.inputs, name: inner.name, outputs: inner.outputs, state_mutability: inner.state_mutability, }), - LegacyFunctionAbiType::L1Handler => { - RawLegacyAbiEntry::L1Handler(RawLegacyL1Handler { - inputs: inner.inputs, - name: inner.name, - outputs: inner.outputs, - }) - } - LegacyFunctionAbiType::Constructor => { - RawLegacyAbiEntry::Constructor(RawLegacyConstructor { - inputs: inner.inputs, - name: inner.name, - outputs: inner.outputs, - }) - } + LegacyFunctionAbiType::L1Handler => Self::L1Handler(RawLegacyL1Handler { + inputs: inner.inputs, + name: inner.name, + outputs: inner.outputs, + }), + LegacyFunctionAbiType::Constructor => Self::Constructor(RawLegacyConstructor { + inputs: inner.inputs, + name: inner.name, + outputs: inner.outputs, + }), }, - LegacyContractAbiEntry::Event(inner) => RawLegacyAbiEntry::Event(RawLegacyEvent { + LegacyContractAbiEntry::Event(inner) => Self::Event(RawLegacyEvent { data: inner.data, keys: inner.keys, name: inner.name, }), - LegacyContractAbiEntry::Struct(inner) => RawLegacyAbiEntry::Struct(RawLegacyStruct { + LegacyContractAbiEntry::Struct(inner) => Self::Struct(RawLegacyStruct { members: inner .members .into_iter() diff --git a/starknet-core/src/types/eth_address.rs b/starknet-core/src/types/eth_address.rs index c380558a..5bfa95bd 100644 --- a/starknet-core/src/types/eth_address.rs +++ b/starknet-core/src/types/eth_address.rs @@ -2,14 +2,14 @@ use alloc::{fmt::Formatter, format}; use core::str::FromStr; use serde::{de::Visitor, Deserialize, Serialize}; -use starknet_ff::FieldElement; +use starknet_types_core::felt::Felt; // 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF -const MAX_L1_ADDRESS: FieldElement = FieldElement::from_mont([ - 18406070939574861858, - 74766790688767, - 18446743936270598144, +const MAX_L1_ADDRESS: Felt = Felt::from_raw([ 461478224317121089, + 18446743936270598144, + 74766790688767, + 18406070939574861858, ]); #[derive(Debug, Clone, PartialEq, Eq)] @@ -58,7 +58,7 @@ mod errors { impl Display for FromFieldElementError { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - write!(f, "FieldElement value out of range") + write!(f, "Felt value out of range") } } @@ -79,11 +79,11 @@ impl EthAddress { hex.parse() } - pub fn from_felt(felt: &FieldElement) -> Result { + pub fn from_felt(felt: &Felt) -> Result { felt.try_into() } - pub fn as_bytes(&self) -> &[u8; 20] { + pub const fn as_bytes(&self) -> &[u8; 20] { &self.inner } } @@ -109,7 +109,7 @@ impl<'de> Deserialize<'de> for EthAddress { impl<'de> Visitor<'de> for EthAddressVisitor { type Value = EthAddress; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string") } @@ -144,18 +144,18 @@ impl FromStr for EthAddress { } } -impl TryFrom for EthAddress { +impl TryFrom for EthAddress { type Error = FromFieldElementError; - fn try_from(value: FieldElement) -> Result { + fn try_from(value: Felt) -> Result { (&value).try_into() } } -impl TryFrom<&FieldElement> for EthAddress { +impl TryFrom<&Felt> for EthAddress { type Error = FromFieldElementError; - fn try_from(value: &FieldElement) -> Result { + fn try_from(value: &Felt) -> Result { if value <= &MAX_L1_ADDRESS { let mut buffer = [0u8; 20]; buffer.copy_from_slice(&value.to_bytes_be()[12..]); @@ -166,10 +166,10 @@ impl TryFrom<&FieldElement> for EthAddress { } } -impl From for FieldElement { +impl From for Felt { fn from(value: EthAddress) -> Self { // Safe to unwrap here as the value is never out of range - FieldElement::from_byte_slice_be(&value.inner).unwrap() + Self::from_bytes_be_slice(&value.inner) } } @@ -196,12 +196,11 @@ impl From<[u8; 20]> for EthAddress { #[cfg(test)] mod tests { - use super::{EthAddress, FromBytesSliceError, FromFieldElementError}; + use super::{EthAddress, Felt, FromBytesSliceError, FromFieldElementError}; use alloc::vec::*; use hex_literal::hex; - use starknet_ff::FieldElement; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] @@ -272,7 +271,7 @@ mod tests { assert_eq!( EthAddress::from_hex("0xb9fa6e54025b4f0829d8e1b42e8b846914659632").unwrap(), EthAddress::from_felt( - &FieldElement::from_hex_be("0xb9fa6e54025b4f0829d8e1b42e8b846914659632").unwrap() + &Felt::from_hex("0xb9fa6e54025b4f0829d8e1b42e8b846914659632").unwrap() ) .unwrap() ); @@ -282,7 +281,7 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_eth_address_from_felt_error() { match EthAddress::from_felt( - &FieldElement::from_hex_be("0x10000000000000000000000000000000000000000").unwrap(), + &Felt::from_hex("0x10000000000000000000000000000000000000000").unwrap(), ) { Ok(_) => panic!("Expected error, but got Ok"), Err(FromFieldElementError) => {} diff --git a/starknet-core/src/types/execution_result.rs b/starknet-core/src/types/execution_result.rs index 2a757531..b0d56a1c 100644 --- a/starknet-core/src/types/execution_result.rs +++ b/starknet-core/src/types/execution_result.rs @@ -12,10 +12,10 @@ pub enum ExecutionResult { } impl ExecutionResult { - pub fn status(&self) -> TransactionExecutionStatus { + pub const fn status(&self) -> TransactionExecutionStatus { match self { - ExecutionResult::Succeeded => TransactionExecutionStatus::Succeeded, - ExecutionResult::Reverted { .. } => TransactionExecutionStatus::Reverted, + Self::Succeeded => TransactionExecutionStatus::Succeeded, + Self::Reverted { .. } => TransactionExecutionStatus::Reverted, } } @@ -25,8 +25,8 @@ impl ExecutionResult { /// variant. pub fn revert_reason(&self) -> Option<&str> { match self { - ExecutionResult::Succeeded => None, - ExecutionResult::Reverted { reason } => Some(reason), + Self::Succeeded => None, + Self::Reverted { reason } => Some(reason), } } } diff --git a/starknet-core/src/types/hash_256.rs b/starknet-core/src/types/hash_256.rs index c8ccc99e..b6ad9061 100644 --- a/starknet-core/src/types/hash_256.rs +++ b/starknet-core/src/types/hash_256.rs @@ -5,7 +5,7 @@ use alloc::{ }; use serde::{de::Visitor, Deserialize, Serialize}; -use starknet_ff::FieldElement; +use starknet_types_core::felt::Felt; const HASH_256_BYTE_COUNT: usize = 32; @@ -49,7 +49,7 @@ mod errors { impl Display for ToFieldElementError { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - write!(f, "hash value out of range for FieldElement") + write!(f, "hash value out of range for Felt") } } } @@ -64,11 +64,11 @@ impl Hash256 { hex.parse() } - pub fn from_felt(felt: &FieldElement) -> Self { + pub fn from_felt(felt: &Felt) -> Self { felt.into() } - pub fn as_bytes(&self) -> &[u8; HASH_256_BYTE_COUNT] { + pub const fn as_bytes(&self) -> &[u8; HASH_256_BYTE_COUNT] { &self.inner } } @@ -78,7 +78,11 @@ impl Serialize for Hash256 { where S: serde::Serializer, { - serializer.serialize_str(&format!("0x{}", hex::encode(self.inner))) + if serializer.is_human_readable() { + serializer.serialize_str(&format!("0x{}", hex::encode(self.inner))) + } else { + serializer.serialize_bytes(self.as_bytes()) + } } } @@ -87,15 +91,19 @@ impl<'de> Deserialize<'de> for Hash256 { where D: serde::Deserializer<'de>, { - deserializer.deserialize_any(Hash256Visitor) + if deserializer.is_human_readable() { + deserializer.deserialize_any(Hash256Visitor) + } else { + deserializer.deserialize_bytes(Hash256Visitor) + } } } impl<'de> Visitor<'de> for Hash256Visitor { type Value = Hash256; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { - write!(formatter, "string") + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { + write!(formatter, "string, or an array of u8") } fn visit_str(self, v: &str) -> Result @@ -105,6 +113,12 @@ impl<'de> Visitor<'de> for Hash256Visitor { v.parse() .map_err(|err| serde::de::Error::custom(format!("{}", err))) } + + fn visit_bytes(self, v: &[u8]) -> Result { + <[u8; HASH_256_BYTE_COUNT]>::try_from(v) + .map(Hash256::from_bytes) + .map_err(serde::de::Error::custom) + } } impl FromStr for Hash256 { @@ -148,19 +162,19 @@ impl Display for Hash256 { } } -impl From for Hash256 { - fn from(value: FieldElement) -> Self { +impl From for Hash256 { + fn from(value: Felt) -> Self { (&value).into() } } -impl From<&FieldElement> for Hash256 { - fn from(value: &FieldElement) -> Self { - value.to_bytes_be().into() +impl From<&Felt> for Hash256 { + fn from(value: &Felt) -> Self { + Self::from_bytes(value.to_bytes_be()) } } -impl TryFrom for FieldElement { +impl TryFrom for Felt { type Error = ToFieldElementError; fn try_from(value: Hash256) -> Result { @@ -168,11 +182,11 @@ impl TryFrom for FieldElement { } } -impl TryFrom<&Hash256> for FieldElement { +impl TryFrom<&Hash256> for Felt { type Error = ToFieldElementError; fn try_from(value: &Hash256) -> Result { - FieldElement::from_bytes_be(&value.inner).map_err(|_| ToFieldElementError) + Ok(Self::from_bytes_be(&value.inner)) } } @@ -184,9 +198,9 @@ impl From<[u8; HASH_256_BYTE_COUNT]> for Hash256 { #[cfg(test)] mod tests { - use super::{FromHexError, Hash256, HASH_256_BYTE_COUNT}; + use super::{Felt, FromHexError, Hash256, HASH_256_BYTE_COUNT}; - use starknet_ff::FieldElement; + use hex_literal::hex; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] @@ -198,7 +212,7 @@ mod tests { "25c5b1592b1743b62d7fabd4373d98219c2ff3750f49ec0608a8355fa3bb060f5", ]; - for item in test_data.into_iter() { + for item in test_data { match Hash256::from_hex(item) { Err(FromHexError::UnexpectedLength) => {} _ => panic!("Unexpected test result"), @@ -216,7 +230,7 @@ mod tests { "0x?5c5b1592b1743b62d7fabd4373d98219c2f63750f49ec0608a8355fa3bb060", ]; - for item in test_data.into_iter() { + for item in test_data { match Hash256::from_hex(item) { Err(FromHexError::InvalidHexString) => {} _ => panic!("Unexpected test result"), @@ -227,13 +241,12 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_hash_256_from_felt() { - // Create a `FieldElement` from a hexadecimal string representation - let felt = FieldElement::from_hex_be( - "0x01a736d6ed154502257f02b1ccdf4d9d1089f80811cd6acad48e6b6a9d1f2003", - ) - .unwrap(); + // Create a `Felt` from a hexadecimal string representation + let felt = + Felt::from_hex("0x01a736d6ed154502257f02b1ccdf4d9d1089f80811cd6acad48e6b6a9d1f2003") + .unwrap(); - // Convert the `FieldElement` to bytes and then to a vector + // Convert the `Felt` to bytes and then to a vector let bytes = (felt.to_bytes_be()).to_vec(); // Convert bytes to a fixed-size array representing `Hash256` @@ -243,7 +256,35 @@ mod tests { // Convert `Hash256` bytes to `Hash256` struct let hash_256: Hash256 = hash_bytes.into(); - // Assert that the conversion from the `FieldElement` to `Hash256` is successful + // Assert that the conversion from the `Felt` to `Hash256` is successful assert_eq!(Hash256::from_felt(&felt), hash_256); } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_ser() { + let r = bincode::serialize(&Hash256::from_bytes(hex!( + "1111111111111111111111111111111111111111111111111111111111111111" + ))) + .unwrap(); + assert_eq!( + r, + hex!( + "2000000000000000 1111111111111111111111111111111111111111111111111111111111111111" + ) + ); + } + + #[test] + #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] + fn bin_deser() { + let r = bincode::deserialize::(&hex!( + "2000000000000000 1111111111111111111111111111111111111111111111111111111111111111" + )) + .unwrap(); + assert_eq!( + r.inner, + hex!("1111111111111111111111111111111111111111111111111111111111111111") + ); + } } diff --git a/starknet-core/src/types/mod.rs b/starknet-core/src/types/mod.rs index df1e6cc5..0d5321f8 100644 --- a/starknet-core/src/types/mod.rs +++ b/starknet-core/src/types/mod.rs @@ -5,7 +5,7 @@ use serde_with::serde_as; use crate::serde::unsigned_field_element::UfeHex; -pub use starknet_ff::*; +pub use starknet_types_core::felt::*; mod conversions; @@ -97,7 +97,7 @@ pub enum MaybePendingStateUpdate { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct BlockHashAndNumber { #[serde_as(as = "UfeHex")] - pub block_hash: FieldElement, + pub block_hash: Felt, pub block_number: u64, } @@ -123,7 +123,7 @@ pub struct EventsPage { pub struct InvokeTransactionResult { /// The hash of the invoke transaction #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } #[serde_as] @@ -131,10 +131,10 @@ pub struct InvokeTransactionResult { pub struct DeclareTransactionResult { /// The hash of the declare transaction #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The hash of the declared class #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, } #[serde_as] @@ -142,10 +142,10 @@ pub struct DeclareTransactionResult { pub struct DeployTransactionResult { /// The hash of the deploy transaction #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The address of the new contract #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, } #[serde_as] @@ -153,16 +153,16 @@ pub struct DeployTransactionResult { pub struct DeployAccountTransactionResult { /// The hash of the deploy transaction #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, /// The address of the new contract #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, } /// Block hash, number or tag #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BlockId { - Hash(FieldElement), + Hash(Felt), Number(u64), Tag(BlockTag), } @@ -174,14 +174,41 @@ pub enum ContractClass { Legacy(CompressedLegacyContractClass), } +/// Represents the status of a transaction. #[derive(Debug, Clone, PartialEq, Eq)] pub enum TransactionStatus { + /// Transaction received and awaiting processing. Received, + /// Transaction rejected due to validation or other reasons. Rejected, + /// Transaction accepted on Layer 2 with a specific execution status. AcceptedOnL2(TransactionExecutionStatus), + /// Transaction accepted on Layer 1 with a specific execution status. AcceptedOnL1(TransactionExecutionStatus), } +impl TransactionStatus { + /// Returns `true` if the transaction status is `Received`. + pub const fn is_received(&self) -> bool { + matches!(self, Self::Received) + } + + /// Returns `true` if the transaction status is `Rejected`. + pub const fn is_rejected(&self) -> bool { + matches!(self, Self::Rejected) + } + + /// Returns `true` if the transaction status is `AcceptedOnL2`. + pub const fn is_accepted_on_l2(&self) -> bool { + matches!(self, Self::AcceptedOnL2(_)) + } + + /// Returns `true` if the transaction status is `AcceptedOnL1`. + pub const fn is_accepted_on_l1(&self) -> bool { + matches!(self, Self::AcceptedOnL1(_)) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] #[serde(tag = "type")] pub enum Transaction { @@ -309,7 +336,7 @@ pub enum ExecuteInvocation { mod errors { use core::fmt::{Display, Formatter, Result}; - #[derive(Debug, PartialEq)] + #[derive(Debug, PartialEq, Eq)] pub enum ParseMsgToL2Error { EmptyCalldata, FromAddressOutOfRange, @@ -337,17 +364,17 @@ mod errors { pub use errors::ParseMsgToL2Error; impl MaybePendingBlockWithTxHashes { - pub fn transactions(&self) -> &[FieldElement] { + pub fn transactions(&self) -> &[Felt] { match self { - MaybePendingBlockWithTxHashes::Block(block) => &block.transactions, - MaybePendingBlockWithTxHashes::PendingBlock(block) => &block.transactions, + Self::Block(block) => &block.transactions, + Self::PendingBlock(block) => &block.transactions, } } - pub fn l1_gas_price(&self) -> &ResourcePrice { + pub const fn l1_gas_price(&self) -> &ResourcePrice { match self { - MaybePendingBlockWithTxHashes::Block(block) => &block.l1_gas_price, - MaybePendingBlockWithTxHashes::PendingBlock(block) => &block.l1_gas_price, + Self::Block(block) => &block.l1_gas_price, + Self::PendingBlock(block) => &block.l1_gas_price, } } } @@ -355,15 +382,15 @@ impl MaybePendingBlockWithTxHashes { impl MaybePendingBlockWithTxs { pub fn transactions(&self) -> &[Transaction] { match self { - MaybePendingBlockWithTxs::Block(block) => &block.transactions, - MaybePendingBlockWithTxs::PendingBlock(block) => &block.transactions, + Self::Block(block) => &block.transactions, + Self::PendingBlock(block) => &block.transactions, } } - pub fn l1_gas_price(&self) -> &ResourcePrice { + pub const fn l1_gas_price(&self) -> &ResourcePrice { match self { - MaybePendingBlockWithTxs::Block(block) => &block.l1_gas_price, - MaybePendingBlockWithTxs::PendingBlock(block) => &block.l1_gas_price, + Self::Block(block) => &block.l1_gas_price, + Self::PendingBlock(block) => &block.l1_gas_price, } } } @@ -371,100 +398,100 @@ impl MaybePendingBlockWithTxs { impl MaybePendingBlockWithReceipts { pub fn transactions(&self) -> &[TransactionWithReceipt] { match self { - MaybePendingBlockWithReceipts::Block(block) => &block.transactions, - MaybePendingBlockWithReceipts::PendingBlock(block) => &block.transactions, + Self::Block(block) => &block.transactions, + Self::PendingBlock(block) => &block.transactions, } } - pub fn l1_gas_price(&self) -> &ResourcePrice { + pub const fn l1_gas_price(&self) -> &ResourcePrice { match self { - MaybePendingBlockWithReceipts::Block(block) => &block.l1_gas_price, - MaybePendingBlockWithReceipts::PendingBlock(block) => &block.l1_gas_price, + Self::Block(block) => &block.l1_gas_price, + Self::PendingBlock(block) => &block.l1_gas_price, } } } impl TransactionStatus { - pub fn finality_status(&self) -> SequencerTransactionStatus { + pub const fn finality_status(&self) -> SequencerTransactionStatus { match self { - TransactionStatus::Received => SequencerTransactionStatus::Received, - TransactionStatus::Rejected => SequencerTransactionStatus::Rejected, - TransactionStatus::AcceptedOnL2(_) => SequencerTransactionStatus::AcceptedOnL2, - TransactionStatus::AcceptedOnL1(_) => SequencerTransactionStatus::AcceptedOnL1, + Self::Received => SequencerTransactionStatus::Received, + Self::Rejected => SequencerTransactionStatus::Rejected, + Self::AcceptedOnL2(_) => SequencerTransactionStatus::AcceptedOnL2, + Self::AcceptedOnL1(_) => SequencerTransactionStatus::AcceptedOnL1, } } } impl Transaction { - pub fn transaction_hash(&self) -> &FieldElement { + pub const fn transaction_hash(&self) -> &Felt { match self { - Transaction::Invoke(tx) => tx.transaction_hash(), - Transaction::L1Handler(tx) => &tx.transaction_hash, - Transaction::Declare(tx) => tx.transaction_hash(), - Transaction::Deploy(tx) => &tx.transaction_hash, - Transaction::DeployAccount(tx) => tx.transaction_hash(), + Self::Invoke(tx) => tx.transaction_hash(), + Self::L1Handler(tx) => &tx.transaction_hash, + Self::Declare(tx) => tx.transaction_hash(), + Self::Deploy(tx) => &tx.transaction_hash, + Self::DeployAccount(tx) => tx.transaction_hash(), } } } impl InvokeTransaction { - pub fn transaction_hash(&self) -> &FieldElement { + pub const fn transaction_hash(&self) -> &Felt { match self { - InvokeTransaction::V0(tx) => &tx.transaction_hash, - InvokeTransaction::V1(tx) => &tx.transaction_hash, - InvokeTransaction::V3(tx) => &tx.transaction_hash, + Self::V0(tx) => &tx.transaction_hash, + Self::V1(tx) => &tx.transaction_hash, + Self::V3(tx) => &tx.transaction_hash, } } } impl DeclareTransaction { - pub fn transaction_hash(&self) -> &FieldElement { + pub const fn transaction_hash(&self) -> &Felt { match self { - DeclareTransaction::V0(tx) => &tx.transaction_hash, - DeclareTransaction::V1(tx) => &tx.transaction_hash, - DeclareTransaction::V2(tx) => &tx.transaction_hash, - DeclareTransaction::V3(tx) => &tx.transaction_hash, + Self::V0(tx) => &tx.transaction_hash, + Self::V1(tx) => &tx.transaction_hash, + Self::V2(tx) => &tx.transaction_hash, + Self::V3(tx) => &tx.transaction_hash, } } } impl DeployAccountTransaction { - pub fn transaction_hash(&self) -> &FieldElement { + pub const fn transaction_hash(&self) -> &Felt { match self { - DeployAccountTransaction::V1(tx) => &tx.transaction_hash, - DeployAccountTransaction::V3(tx) => &tx.transaction_hash, + Self::V1(tx) => &tx.transaction_hash, + Self::V3(tx) => &tx.transaction_hash, } } } impl TransactionReceipt { - pub fn transaction_hash(&self) -> &FieldElement { + pub const fn transaction_hash(&self) -> &Felt { match self { - TransactionReceipt::Invoke(receipt) => &receipt.transaction_hash, - TransactionReceipt::L1Handler(receipt) => &receipt.transaction_hash, - TransactionReceipt::Declare(receipt) => &receipt.transaction_hash, - TransactionReceipt::Deploy(receipt) => &receipt.transaction_hash, - TransactionReceipt::DeployAccount(receipt) => &receipt.transaction_hash, + Self::Invoke(receipt) => &receipt.transaction_hash, + Self::L1Handler(receipt) => &receipt.transaction_hash, + Self::Declare(receipt) => &receipt.transaction_hash, + Self::Deploy(receipt) => &receipt.transaction_hash, + Self::DeployAccount(receipt) => &receipt.transaction_hash, } } - pub fn finality_status(&self) -> &TransactionFinalityStatus { + pub const fn finality_status(&self) -> &TransactionFinalityStatus { match self { - TransactionReceipt::Invoke(receipt) => &receipt.finality_status, - TransactionReceipt::L1Handler(receipt) => &receipt.finality_status, - TransactionReceipt::Declare(receipt) => &receipt.finality_status, - TransactionReceipt::Deploy(receipt) => &receipt.finality_status, - TransactionReceipt::DeployAccount(receipt) => &receipt.finality_status, + Self::Invoke(receipt) => &receipt.finality_status, + Self::L1Handler(receipt) => &receipt.finality_status, + Self::Declare(receipt) => &receipt.finality_status, + Self::Deploy(receipt) => &receipt.finality_status, + Self::DeployAccount(receipt) => &receipt.finality_status, } } - pub fn execution_result(&self) -> &ExecutionResult { + pub const fn execution_result(&self) -> &ExecutionResult { match self { - TransactionReceipt::Invoke(receipt) => &receipt.execution_result, - TransactionReceipt::L1Handler(receipt) => &receipt.execution_result, - TransactionReceipt::Declare(receipt) => &receipt.execution_result, - TransactionReceipt::Deploy(receipt) => &receipt.execution_result, - TransactionReceipt::DeployAccount(receipt) => &receipt.execution_result, + Self::Invoke(receipt) => &receipt.execution_result, + Self::L1Handler(receipt) => &receipt.execution_result, + Self::Declare(receipt) => &receipt.execution_result, + Self::Deploy(receipt) => &receipt.execution_result, + Self::DeployAccount(receipt) => &receipt.execution_result, } } } @@ -488,44 +515,44 @@ impl L1HandlerTransaction { } } -impl AsRef for BlockId { - fn as_ref(&self) -> &BlockId { +impl AsRef for BlockId { + fn as_ref(&self) -> &Self { self } } -impl AsRef for FunctionCall { - fn as_ref(&self) -> &FunctionCall { +impl AsRef for FunctionCall { + fn as_ref(&self) -> &Self { self } } -impl AsRef for MsgFromL1 { - fn as_ref(&self) -> &MsgFromL1 { +impl AsRef for MsgFromL1 { + fn as_ref(&self) -> &Self { self } } -impl AsRef for BroadcastedTransaction { - fn as_ref(&self) -> &BroadcastedTransaction { +impl AsRef for BroadcastedTransaction { + fn as_ref(&self) -> &Self { self } } -impl AsRef for BroadcastedInvokeTransaction { - fn as_ref(&self) -> &BroadcastedInvokeTransaction { +impl AsRef for BroadcastedInvokeTransaction { + fn as_ref(&self) -> &Self { self } } -impl AsRef for BroadcastedDeclareTransaction { - fn as_ref(&self) -> &BroadcastedDeclareTransaction { +impl AsRef for BroadcastedDeclareTransaction { + fn as_ref(&self) -> &Self { self } } -impl AsRef for BroadcastedDeployAccountTransaction { - fn as_ref(&self) -> &BroadcastedDeployAccountTransaction { +impl AsRef for BroadcastedDeployAccountTransaction { + fn as_ref(&self) -> &Self { self } } @@ -545,7 +572,7 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_felt_to_string() { - let felt = FieldElement::from_dec_str("123456").unwrap(); + let felt = Felt::from_dec_str("123456").unwrap(); assert_eq!(format!("{}", felt), "123456"); assert_eq!(format!("{:x}", felt), "1e240"); @@ -580,28 +607,26 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_parse_msg_to_l2() { let l1_handler_tx = L1HandlerTransaction { - transaction_hash: FieldElement::from_hex_be( + transaction_hash: Felt::from_hex( "0x374286ae28f201e61ffbc5b022cc9701208640b405ea34ea9799f97d5d2d23c", ) .unwrap(), - version: FieldElement::ZERO, + version: Felt::ZERO, nonce: 775628, - contract_address: FieldElement::from_hex_be( + contract_address: Felt::from_hex( "0x73314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82", ) .unwrap(), - entry_point_selector: FieldElement::from_hex_be( + entry_point_selector: Felt::from_hex( "0x2d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5", ) .unwrap(), calldata: vec![ - FieldElement::from_hex_be("0xc3511006c04ef1d78af4c8e0e74ec18a6e64ff9e").unwrap(), - FieldElement::from_hex_be( - "0x689ead7d814e51ed93644bc145f0754839b8dcb340027ce0c30953f38f55d7", - ) - .unwrap(), - FieldElement::from_hex_be("0x2c68af0bb140000").unwrap(), - FieldElement::from_hex_be("0x0").unwrap(), + Felt::from_hex("0xc3511006c04ef1d78af4c8e0e74ec18a6e64ff9e").unwrap(), + Felt::from_hex("0x689ead7d814e51ed93644bc145f0754839b8dcb340027ce0c30953f38f55d7") + .unwrap(), + Felt::from_hex("0x2c68af0bb140000").unwrap(), + Felt::from_hex("0x0").unwrap(), ], }; @@ -618,17 +643,17 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_parse_msg_to_l2_empty_calldata_error() { let l1_handler_tx = L1HandlerTransaction { - transaction_hash: FieldElement::from_hex_be( + transaction_hash: Felt::from_hex( "0x374286ae28f201e61ffbc5b022cc9701208640b405ea34ea9799f97d5d2d23c", ) .unwrap(), - version: FieldElement::ZERO, + version: Felt::ZERO, nonce: 775628, - contract_address: FieldElement::from_hex_be( + contract_address: Felt::from_hex( "0x73314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82", ) .unwrap(), - entry_point_selector: FieldElement::from_hex_be( + entry_point_selector: Felt::from_hex( "0x2d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5", ) .unwrap(), @@ -644,30 +669,28 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_parse_msg_to_l2_from_address_out_of_range_error() { let l1_handler_tx = L1HandlerTransaction { - transaction_hash: FieldElement::from_hex_be( + transaction_hash: Felt::from_hex( "0x374286ae28f201e61ffbc5b022cc9701208640b405ea34ea9799f97d5d2d23c", ) .unwrap(), - version: FieldElement::ZERO, + version: Felt::ZERO, nonce: 775628, - contract_address: FieldElement::from_hex_be( + contract_address: Felt::from_hex( "0x73314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82", ) .unwrap(), - entry_point_selector: FieldElement::from_hex_be( + entry_point_selector: Felt::from_hex( "0x2d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5", ) .unwrap(), calldata: vec![ // Incorrect from address format, causing the conversion error // Max address + 1 - FieldElement::from_hex_be("0x10000000000000000000000000000000000000000").unwrap(), - FieldElement::from_hex_be( - "0x689ead7d814e51ed93644bc145f0754839b8dcb340027ce0c30953f38f55d7", - ) - .unwrap(), - FieldElement::from_hex_be("0x2c68af0bb140000").unwrap(), - FieldElement::from_hex_be("0x0").unwrap(), + Felt::from_hex("0x10000000000000000000000000000000000000000").unwrap(), + Felt::from_hex("0x689ead7d814e51ed93644bc145f0754839b8dcb340027ce0c30953f38f55d7") + .unwrap(), + Felt::from_hex("0x2c68af0bb140000").unwrap(), + Felt::from_hex("0x0").unwrap(), ], }; diff --git a/starknet-core/src/types/msg.rs b/starknet-core/src/types/msg.rs index f57b39c8..c34919e9 100644 --- a/starknet-core/src/types/msg.rs +++ b/starknet-core/src/types/msg.rs @@ -1,23 +1,23 @@ use alloc::vec::*; use sha3::{Digest, Keccak256}; -use starknet_ff::FieldElement; +use starknet_types_core::felt::Felt; use super::{EthAddress, Hash256, MsgToL1}; #[derive(Debug, Clone)] pub struct MsgToL2 { pub from_address: EthAddress, - pub to_address: FieldElement, - pub selector: FieldElement, - pub payload: Vec, + pub to_address: Felt, + pub selector: Felt, + pub payload: Vec, pub nonce: u64, } impl MsgToL2 { /// Calculates the message hash based on the algorithm documented here: /// - /// https://docs.starknet.io/documentation/architecture_and_concepts/L1-L2_Communication/messaging-mechanism/ + /// pub fn hash(&self) -> Hash256 { let mut hasher = Keccak256::new(); @@ -40,7 +40,7 @@ impl MsgToL2 { hasher.update((self.payload.len() as u64).to_be_bytes()); // Payload - for item in self.payload.iter() { + for item in &self.payload { hasher.update(item.to_bytes_be()); } @@ -54,7 +54,7 @@ impl MsgToL2 { impl MsgToL1 { /// Calculates the message hash based on the algorithm documented here: /// - /// https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/messaging-mechanism/#structure_and_hashing_l2-l1 + /// pub fn hash(&self) -> Hash256 { let mut hasher = Keccak256::new(); @@ -69,7 +69,7 @@ impl MsgToL1 { hasher.update((self.payload.len() as u64).to_be_bytes()); // Payload - for item in self.payload.iter() { + for item in &self.payload { hasher.update(item.to_bytes_be()); } @@ -92,21 +92,19 @@ mod tests { let msg = MsgToL2 { from_address: EthAddress::from_hex("0xc3511006C04EF1d78af4C8E0e74Ec18A6E64Ff9e") .unwrap(), - to_address: FieldElement::from_hex_be( + to_address: Felt::from_hex( "0x73314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82", ) .unwrap(), - selector: FieldElement::from_hex_be( + selector: Felt::from_hex( "0x2d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5", ) .unwrap(), payload: vec![ - FieldElement::from_hex_be( - "0x689ead7d814e51ed93644bc145f0754839b8dcb340027ce0c30953f38f55d7", - ) - .unwrap(), - FieldElement::from_hex_be("0x2c68af0bb140000").unwrap(), - FieldElement::from_hex_be("0x0").unwrap(), + Felt::from_hex("0x689ead7d814e51ed93644bc145f0754839b8dcb340027ce0c30953f38f55d7") + .unwrap(), + Felt::from_hex("0x2c68af0bb140000").unwrap(), + Felt::from_hex("0x0").unwrap(), ], nonce: 775628, }; @@ -125,21 +123,21 @@ mod tests { // Goerli-1 tx (L2): 4e0bbc07ff29e5df13dfbcb7e4746fdde52c3649a6a69bd86b15397769722fd let msg = MsgToL1 { - from_address: FieldElement::from_hex_be( + from_address: Felt::from_hex( "0x0164cba33fb7152531f6b4cfc3fff26b4d7b26b4900e0881042edd607b428a92", ) .unwrap(), - to_address: FieldElement::from_hex_be( + to_address: Felt::from_hex( "0x000000000000000000000000b6dbfaa86bb683152e4fc2401260f9ca249519c0", ) .unwrap(), payload: vec![ - FieldElement::from_hex_be("0x0").unwrap(), - FieldElement::from_hex_be("0x0").unwrap(), - FieldElement::from_hex_be("0x0182b8").unwrap(), - FieldElement::from_hex_be("0x0").unwrap(), - FieldElement::from_hex_be("0x0384").unwrap(), - FieldElement::from_hex_be("0x0").unwrap(), + Felt::from_hex("0x0").unwrap(), + Felt::from_hex("0x0").unwrap(), + Felt::from_hex("0x0182b8").unwrap(), + Felt::from_hex("0x0").unwrap(), + Felt::from_hex("0x0384").unwrap(), + Felt::from_hex("0x0").unwrap(), ], }; diff --git a/starknet-core/src/types/receipt_block.rs b/starknet-core/src/types/receipt_block.rs index 56bd1ba5..a6216dfe 100644 --- a/starknet-core/src/types/receipt_block.rs +++ b/starknet-core/src/types/receipt_block.rs @@ -1,71 +1,70 @@ use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use crate::types::FieldElement; +use crate::serde::unsigned_field_element::UfeHex; +use starknet_types_core::felt::Felt; /// A more idiomatic way to access `execution_status` and `revert_reason`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ReceiptBlock { Pending, - Block { - block_hash: FieldElement, - block_number: u64, - }, + Block { block_hash: Felt, block_number: u64 }, } impl ReceiptBlock { /// Returns `true` if and only if it's the `Pending` variant. - pub fn is_pending(&self) -> bool { + pub const fn is_pending(&self) -> bool { match self { - ReceiptBlock::Pending => true, - ReceiptBlock::Block { .. } => false, + Self::Pending => true, + Self::Block { .. } => false, } } /// Returns `true` if and only if it's the `Block` variant. - pub fn is_block(&self) -> bool { + pub const fn is_block(&self) -> bool { match self { - ReceiptBlock::Pending => false, - ReceiptBlock::Block { .. } => true, + Self::Pending => false, + Self::Block { .. } => true, } } /// Returns `None` if block is not `Block`. /// /// A more idiomatic way of accessing the block hash is to match the `Block` enum variant. - pub fn block_hash(&self) -> Option { + pub const fn block_hash(&self) -> Option { match self { - ReceiptBlock::Pending => None, - ReceiptBlock::Block { block_hash, .. } => Some(*block_hash), + Self::Pending => None, + Self::Block { block_hash, .. } => Some(*block_hash), } } /// Returns `None` if block is not `Block`. /// /// A more idiomatic way of accessing the block number is to match the `Block` enum variant. - pub fn block_number(&self) -> Option { + pub const fn block_number(&self) -> Option { match self { - ReceiptBlock::Pending => None, - ReceiptBlock::Block { block_number, .. } => Some(*block_number), + Self::Pending => None, + Self::Block { block_number, .. } => Some(*block_number), } } } +#[serde_as] +#[derive(Serialize, Deserialize)] +#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] +struct Raw { + #[serde(skip_serializing_if = "Option::is_none")] + #[serde_as(as = "Option")] + block_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + block_number: Option, +} + impl Serialize for ReceiptBlock { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { - #[derive(Serialize)] - #[serde_as] - struct Raw<'a> { - #[serde_as(as = "Option")] - #[serde(skip_serializing_if = "Option::is_none")] - block_hash: Option<&'a FieldElement>, - #[serde(skip_serializing_if = "Option::is_none")] - block_number: Option<&'a u64>, - } - let raw = match self { Self::Pending => Raw { block_hash: None, @@ -75,8 +74,8 @@ impl Serialize for ReceiptBlock { block_hash, block_number, } => Raw { - block_hash: Some(block_hash), - block_number: Some(block_number), + block_hash: Some(*block_hash), + block_number: Some(*block_number), }, }; @@ -89,17 +88,6 @@ impl<'de> Deserialize<'de> for ReceiptBlock { where D: serde::Deserializer<'de>, { - #[derive(Deserialize)] - #[serde_as] - #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] - struct Raw { - #[serde_as(as = "Option")] - #[serde(skip_serializing_if = "Option::is_none")] - block_hash: Option, - #[serde(skip_serializing_if = "Option::is_none")] - block_number: Option, - } - let raw = Raw::deserialize(deserializer)?; match (raw.block_hash, raw.block_number) { diff --git a/starknet-core/src/types/serde_impls.rs b/starknet-core/src/types/serde_impls.rs index 589cadb3..925321c8 100644 --- a/starknet-core/src/types/serde_impls.rs +++ b/starknet-core/src/types/serde_impls.rs @@ -58,7 +58,7 @@ impl<'de> DeserializeAs<'de, u128> for NumAsHex { impl<'de> Visitor<'de> for NumAsHexVisitorU64 { type Value = u64; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string or number") } @@ -98,7 +98,7 @@ impl<'de> Visitor<'de> for NumAsHexVisitorU64 { impl<'de> Visitor<'de> for NumAsHexVisitorU128 { type Value = u128; - fn expecting(&self, formatter: &mut Formatter) -> alloc::fmt::Result { + fn expecting(&self, formatter: &mut Formatter<'_>) -> alloc::fmt::Result { write!(formatter, "string or number") } @@ -128,8 +128,8 @@ impl Serialize for SyncStatusType { S: serde::Serializer, { match self { - SyncStatusType::NotSyncing => serializer.serialize_bool(false), - SyncStatusType::Syncing(sync_status) => SyncStatus::serialize(sync_status, serializer), + Self::NotSyncing => serializer.serialize_bool(false), + Self::Syncing(sync_status) => SyncStatus::serialize(sync_status, serializer), } } } @@ -145,15 +145,16 @@ impl<'de> Deserialize<'de> for SyncStatusType { false => Ok(Self::NotSyncing), }, - SyncStatusTypeDe::SyncStatus(value) => Ok(SyncStatusType::Syncing(value)), + SyncStatusTypeDe::SyncStatus(value) => Ok(Self::Syncing(value)), } } } mod block_id { - use crate::{serde::unsigned_field_element::UfeHex, types::FieldElement}; + use crate::serde::unsigned_field_element::UfeHex; use serde::{Deserialize, Deserializer, Serialize}; use serde_with::serde_as; + use starknet_types_core::felt::Felt; use crate::types::{BlockId, BlockTag}; @@ -170,7 +171,7 @@ mod block_id { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] struct BlockHash { #[serde_as(as = "UfeHex")] - block_hash: FieldElement, + block_hash: Felt, } #[derive(Serialize, Deserialize)] @@ -232,19 +233,19 @@ mod transaction_status { S: Serializer, { let raw = match self { - TransactionStatus::Received => Raw { + Self::Received => Raw { finality_status: SequencerTransactionStatus::Received, execution_status: None, }, - TransactionStatus::Rejected => Raw { + Self::Rejected => Raw { finality_status: SequencerTransactionStatus::Rejected, execution_status: None, }, - TransactionStatus::AcceptedOnL2(exe) => Raw { + Self::AcceptedOnL2(exe) => Raw { finality_status: SequencerTransactionStatus::AcceptedOnL2, execution_status: Some(*exe), }, - TransactionStatus::AcceptedOnL1(exe) => Raw { + Self::AcceptedOnL1(exe) => Raw { finality_status: SequencerTransactionStatus::AcceptedOnL1, execution_status: Some(*exe), }, @@ -400,9 +401,10 @@ mod enum_ser_impls { mod tests { use serde::Deserialize; use serde_with::serde_as; + use starknet_types_core::felt::Felt; use super::{ - super::{BlockId, BlockTag, FieldElement}, + super::{BlockId, BlockTag}, NumAsHex, }; @@ -411,15 +413,13 @@ mod tests { fn test_blockid_serde() { for (block_id, json) in [ ( - BlockId::Hash(FieldElement::from_hex_be("0x1234").unwrap()), + BlockId::Hash(Felt::from_hex("0x1234").unwrap()), "{\"block_hash\":\"0x1234\"}", ), (BlockId::Number(1234), "{\"block_number\":1234}"), (BlockId::Tag(BlockTag::Latest), "\"latest\""), (BlockId::Tag(BlockTag::Pending), "\"pending\""), - ] - .into_iter() - { + ] { assert_eq!(serde_json::to_string(&block_id).unwrap(), json); assert_eq!(serde_json::from_str::(json).unwrap(), block_id); } @@ -432,7 +432,7 @@ mod tests { #[derive(Debug, PartialEq, Eq, Deserialize)] struct Value(#[serde_as(as = "NumAsHex")] u64); - for (num, json) in [(Value(100), "\"0x64\""), (Value(100), "100")].into_iter() { + for (num, json) in [(Value(100), "\"0x64\""), (Value(100), "100")] { assert_eq!(serde_json::from_str::(json).unwrap(), num); } } diff --git a/starknet-core/src/types/u256.rs b/starknet-core/src/types/u256.rs index eea783cb..f02b87c0 100644 --- a/starknet-core/src/types/u256.rs +++ b/starknet-core/src/types/u256.rs @@ -1,7 +1,8 @@ use core::{fmt::Display, str}; use crypto_bigint::{ArrayEncoding, CheckedAdd, CheckedMul, CheckedSub, Zero}; -use starknet_ff::FieldElement; + +use crate::types::Felt; /// 256-bit unsiged integer. /// @@ -11,7 +12,7 @@ pub struct U256(crypto_bigint::U256); impl U256 { #[cfg(target_pointer_width = "64")] - pub fn from_words(low: u128, high: u128) -> Self { + pub const fn from_words(low: u128, high: u128) -> Self { Self(crypto_bigint::U256::from_words([ low as u64, (low >> 64) as u64, @@ -21,7 +22,7 @@ impl U256 { } #[cfg(target_pointer_width = "32")] - pub fn from_words(low: u128, high: u128) -> Self { + pub const fn from_words(low: u128, high: u128) -> Self { Self(crypto_bigint::U256::from_words([ low as u32, (low >> 32) as u32, @@ -34,83 +35,83 @@ impl U256 { ])) } - pub fn low(&self) -> u128 { + pub const fn low(&self) -> u128 { let words = u256_to_u64_array(&self.0); words[0] as u128 + ((words[1] as u128) << 64) } - pub fn high(&self) -> u128 { + pub const fn high(&self) -> u128 { let words = u256_to_u64_array(&self.0); words[2] as u128 + ((words[3] as u128) << 64) } } -impl core::ops::Add for U256 { - type Output = U256; +impl core::ops::Add for U256 { + type Output = Self; - fn add(self, rhs: U256) -> Self::Output { + fn add(self, rhs: Self) -> Self::Output { Self(self.0.checked_add(&rhs.0).unwrap()) } } -impl core::ops::AddAssign for U256 { - fn add_assign(&mut self, rhs: U256) { +impl core::ops::AddAssign for U256 { + fn add_assign(&mut self, rhs: Self) { self.0 = self.0.checked_add(&rhs.0).unwrap() } } -impl core::ops::Sub for U256 { - type Output = U256; +impl core::ops::Sub for U256 { + type Output = Self; - fn sub(self, rhs: U256) -> Self::Output { + fn sub(self, rhs: Self) -> Self::Output { Self(self.0.checked_sub(&rhs.0).unwrap()) } } -impl core::ops::SubAssign for U256 { - fn sub_assign(&mut self, rhs: U256) { +impl core::ops::SubAssign for U256 { + fn sub_assign(&mut self, rhs: Self) { self.0 = self.0.checked_sub(&rhs.0).unwrap() } } -impl core::ops::Mul for U256 { - type Output = U256; +impl core::ops::Mul for U256 { + type Output = Self; - fn mul(self, rhs: U256) -> Self::Output { + fn mul(self, rhs: Self) -> Self::Output { Self(self.0.checked_mul(&rhs.0).unwrap()) } } -impl core::ops::MulAssign for U256 { - fn mul_assign(&mut self, rhs: U256) { +impl core::ops::MulAssign for U256 { + fn mul_assign(&mut self, rhs: Self) { self.0 = self.0.checked_mul(&rhs.0).unwrap() } } -impl core::ops::Div for U256 { - type Output = U256; +impl core::ops::Div for U256 { + type Output = Self; - fn div(self, rhs: U256) -> Self::Output { + fn div(self, rhs: Self) -> Self::Output { Self(self.0.checked_div(&rhs.0).unwrap()) } } -impl core::ops::DivAssign for U256 { - fn div_assign(&mut self, rhs: U256) { +impl core::ops::DivAssign for U256 { + fn div_assign(&mut self, rhs: Self) { self.0 = self.0.checked_div(&rhs.0).unwrap() } } -impl core::ops::Rem for U256 { - type Output = U256; +impl core::ops::Rem for U256 { + type Output = Self; - fn rem(self, rhs: U256) -> Self::Output { + fn rem(self, rhs: Self) -> Self::Output { Self(self.0.checked_rem(&rhs.0).unwrap()) } } -impl core::ops::RemAssign for U256 { - fn rem_assign(&mut self, rhs: U256) { +impl core::ops::RemAssign for U256 { + fn rem_assign(&mut self, rhs: Self) { self.0 = self.0.checked_rem(&rhs.0).unwrap() } } @@ -242,8 +243,8 @@ impl From for U256 { } } -impl From for U256 { - fn from(value: FieldElement) -> Self { +impl From for U256 { + fn from(value: Felt) -> Self { Self(crypto_bigint::U256::from_be_byte_array( value.to_bytes_be().into(), )) @@ -252,13 +253,13 @@ impl From for U256 { #[cfg(target_pointer_width = "64")] #[inline] -fn u256_to_u64_array(num: &crypto_bigint::U256) -> [u64; 4] { +const fn u256_to_u64_array(num: &crypto_bigint::U256) -> [u64; 4] { num.to_words() } #[cfg(target_pointer_width = "32")] #[inline] -fn u256_to_u64_array(num: &crypto_bigint::U256) -> [u64; 4] { +const fn u256_to_u64_array(num: &crypto_bigint::U256) -> [u64; 4] { unsafe { core::mem::transmute::<[u32; 8], [u64; 4]>(num.to_words()) } } @@ -276,10 +277,7 @@ mod tests { assert_eq!(u256_value, 123u32.into()); assert_eq!(u256_value, 123u64.into()); assert_eq!(u256_value, 123u128.into()); - assert_eq!( - u256_value, - FieldElement::from_dec_str("123").unwrap().into() - ); + assert_eq!(u256_value, Felt::from_dec_str("123").unwrap().into()); } #[test] diff --git a/starknet-core/src/utils.rs b/starknet-core/src/utils.rs index ab836ed5..10bac139 100644 --- a/starknet-core/src/utils.rs +++ b/starknet-core/src/utils.rs @@ -1,27 +1,29 @@ use alloc::string::*; -use crate::{crypto::compute_hash_on_elements, types::FieldElement}; +use crate::crypto::compute_hash_on_elements; use sha3::{Digest, Keccak256}; use starknet_crypto::pedersen_hash; +use starknet_types_core::felt::Felt; +use starknet_types_core::felt::NonZeroFelt; const DEFAULT_ENTRY_POINT_NAME: &str = "__default__"; const DEFAULT_L1_ENTRY_POINT_NAME: &str = "__l1_default__"; // 2 ** 251 - 256 -const ADDR_BOUND: FieldElement = FieldElement::from_mont([ - 18446743986131443745, - 160989183, - 18446744073709255680, +const ADDR_BOUND: NonZeroFelt = NonZeroFelt::from_raw([ 576459263475590224, + 18446744073709255680, + 160989183, + 18446743986131443745, ]); // Cairo string of "STARKNET_CONTRACT_ADDRESS" -const CONTRACT_ADDRESS_PREFIX: FieldElement = FieldElement::from_mont([ - 3829237882463328880, - 17289941567720117366, - 8635008616843941496, +const CONTRACT_ADDRESS_PREFIX: Felt = Felt::from_raw([ 533439743893157637, + 8635008616843941496, + 17289941567720117366, + 3829237882463328880, ]); /// The uniqueness settings for UDC deployments. @@ -33,8 +35,8 @@ pub enum UdcUniqueness { #[derive(Debug, Clone)] pub struct UdcUniqueSettings { - pub deployer_address: FieldElement, - pub udc_contract_address: FieldElement, + pub deployer_address: Felt, + pub udc_contract_address: Felt, } mod errors { @@ -95,7 +97,7 @@ mod errors { pub use errors::{CairoShortStringToFeltError, NonAsciiNameError, ParseCairoShortStringError}; /// A variant of eth-keccak that computes a value that fits in a Starknet field element. -pub fn starknet_keccak(data: &[u8]) -> FieldElement { +pub fn starknet_keccak(data: &[u8]) -> Felt { let mut hasher = Keccak256::new(); hasher.update(data); let mut hash = hasher.finalize(); @@ -104,12 +106,12 @@ pub fn starknet_keccak(data: &[u8]) -> FieldElement { hash[0] &= 0b00000011; // Because we know hash is always 32 bytes - FieldElement::from_bytes_be(unsafe { &*(hash[..].as_ptr() as *const [u8; 32]) }).unwrap() + Felt::from_bytes_be(unsafe { &*(hash[..].as_ptr() as *const [u8; 32]) }) } -pub fn get_selector_from_name(func_name: &str) -> Result { +pub fn get_selector_from_name(func_name: &str) -> Result { if func_name == DEFAULT_ENTRY_POINT_NAME || func_name == DEFAULT_L1_ENTRY_POINT_NAME { - Ok(FieldElement::ZERO) + Ok(Felt::ZERO) } else { let name_bytes = func_name.as_bytes(); if name_bytes.is_ascii() { @@ -120,14 +122,11 @@ pub fn get_selector_from_name(func_name: &str) -> Result Result { +pub fn get_storage_var_address(var_name: &str, args: &[Felt]) -> Result { let var_name_bytes = var_name.as_bytes(); if var_name_bytes.is_ascii() { let mut res = starknet_keccak(var_name_bytes); - for arg in args.iter() { + for arg in args { res = pedersen_hash(&res, arg); } Ok(normalize_address(res)) @@ -136,8 +135,8 @@ pub fn get_storage_var_address( } } -/// Converts Cairo short string to [FieldElement]. -pub fn cairo_short_string_to_felt(str: &str) -> Result { +/// Converts Cairo short string to [`Felt`]. +pub fn cairo_short_string_to_felt(str: &str) -> Result { if !str.is_ascii() { return Err(CairoShortStringToFeltError::NonAsciiCharacter); } @@ -151,12 +150,12 @@ pub fn cairo_short_string_to_felt(str: &str) -> Result Result { - if felt == &FieldElement::ZERO { +/// Converts [`Felt`] to Cairo short string. +pub fn parse_cairo_short_string(felt: &Felt) -> Result { + if felt == &Felt::ZERO { return Ok(String::new()); } @@ -166,7 +165,7 @@ pub fn parse_cairo_short_string(felt: &FieldElement) -> Result Result FieldElement { + salt: Felt, + class_hash: Felt, + constructor_calldata: &[Felt], + deployer_address: Felt, +) -> Felt { normalize_address(compute_hash_on_elements(&[ CONTRACT_ADDRESS_PREFIX, deployer_address, @@ -198,14 +197,14 @@ pub fn get_contract_address( /// Computes the target contract address for deployments through the Universal Deploy Contract. pub fn get_udc_deployed_address( - salt: FieldElement, - class_hash: FieldElement, + salt: Felt, + class_hash: Felt, uniqueness: &UdcUniqueness, - constructor_calldata: &[FieldElement], -) -> FieldElement { + constructor_calldata: &[Felt], +) -> Felt { match uniqueness { UdcUniqueness::NotUnique => { - get_contract_address(salt, class_hash, constructor_calldata, FieldElement::ZERO) + get_contract_address(salt, class_hash, constructor_calldata, Felt::ZERO) } UdcUniqueness::Unique(settings) => { let unique_salt = pedersen_hash(&settings.deployer_address, &salt); @@ -219,8 +218,8 @@ pub fn get_udc_deployed_address( } } -pub fn normalize_address(address: FieldElement) -> FieldElement { - address % ADDR_BOUND +pub fn normalize_address(address: Felt) -> Felt { + address.mod_floor(&ADDR_BOUND) } #[cfg(test)] @@ -232,10 +231,9 @@ mod tests { fn test_starknet_keccak() { // Generated from `cairo-lang` let data = b"execute"; - let expected_hash = FieldElement::from_hex_be( - "0240060cdb34fcc260f41eac7474ee1d7c80b7e3607daff9ac67c7ea2ebb1c44", - ) - .unwrap(); + let expected_hash = + Felt::from_hex("0240060cdb34fcc260f41eac7474ee1d7c80b7e3607daff9ac67c7ea2ebb1c44") + .unwrap(); let hash = starknet_keccak(data); @@ -247,10 +245,9 @@ mod tests { fn test_get_selector_from_name() { // Generated from `cairo-lang` let func_name = "execute"; - let expected_selector = FieldElement::from_hex_be( - "0240060cdb34fcc260f41eac7474ee1d7c80b7e3607daff9ac67c7ea2ebb1c44", - ) - .unwrap(); + let expected_selector = + Felt::from_hex("0240060cdb34fcc260f41eac7474ee1d7c80b7e3607daff9ac67c7ea2ebb1c44") + .unwrap(); let selector = get_selector_from_name(func_name).unwrap(); @@ -260,10 +257,9 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_get_default_selector() { - let default_selector = FieldElement::from_hex_be( - "0000000000000000000000000000000000000000000000000000000000000000", - ) - .unwrap(); + let default_selector = + Felt::from_hex("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap(); assert_eq!( get_selector_from_name("__default__").unwrap(), @@ -291,10 +287,9 @@ mod tests { fn test_get_storage_var_address() { // Generated from `cairo-lang` let var_name = "balance"; - let expected_addr = FieldElement::from_hex_be( - "0x0206f38f7e4f15e87567361213c28f235cccdaa1d7fd34c9db1dfe9489c6a091", - ) - .unwrap(); + let expected_addr = + Felt::from_hex("0x0206f38f7e4f15e87567361213c28f235cccdaa1d7fd34c9db1dfe9489c6a091") + .unwrap(); let addr = get_storage_var_address(var_name, &[]).unwrap(); @@ -306,10 +301,9 @@ mod tests { fn test_get_storage_var_address_with_args() { // Generated from `cairo-lang` let var_name = "balanceOf"; - let expected_addr = FieldElement::from_hex_be( - "0x07de334d65aa93d9185729b424025918b18892418c85b802775d1f0d2be30a1d", - ) - .unwrap(); + let expected_addr = + Felt::from_hex("0x07de334d65aa93d9185729b424025918b18892418c85b802775d1f0d2be30a1d") + .unwrap(); let addr = get_storage_var_address(var_name, &[1234u64.into()]).unwrap(); @@ -330,10 +324,10 @@ mod tests { ), ]; - for (str, felt_dec) in data.into_iter() { + for (str, felt_dec) in data { assert_eq!( cairo_short_string_to_felt(str).unwrap(), - FieldElement::from_dec_str(felt_dec).unwrap() + Felt::from_dec_str(felt_dec).unwrap() ); } } @@ -370,9 +364,9 @@ mod tests { ), ]; - for (str, felt_dec) in data.into_iter() { + for (str, felt_dec) in data { assert_eq!( - parse_cairo_short_string(&FieldElement::from_dec_str(felt_dec).unwrap()).unwrap(), + parse_cairo_short_string(&Felt::from_dec_str(felt_dec).unwrap()).unwrap(), str ); } @@ -383,7 +377,7 @@ mod tests { fn test_parse_cairo_short_string_too_long() { assert!(matches!( parse_cairo_short_string( - &FieldElement::from_hex_be( + &Felt::from_hex( "0x0111111111111111111111111111111111111111111111111111111111111111" ) .unwrap() @@ -397,7 +391,7 @@ mod tests { fn test_parse_cairo_short_string_unexpected_null() { assert!(matches!( parse_cairo_short_string( - &FieldElement::from_hex_be( + &Felt::from_hex( "0x0011111111111111111111111111111111111111111111111111111111110011" ) .unwrap() @@ -411,21 +405,19 @@ mod tests { fn test_get_contract_address() { assert_eq!( get_contract_address( - FieldElement::from_hex_be( + Felt::from_hex( "0x0018a7a329d1d85b621350f2b5fc9c64b2e57dfe708525f0aff2c90de1e5b9c8" ) .unwrap(), - FieldElement::from_hex_be( + Felt::from_hex( "0x0750cd490a7cd1572411169eaa8be292325990d33c5d4733655fe6b926985062" ) .unwrap(), - &[FieldElement::ONE], - FieldElement::ZERO + &[Felt::ONE], + Felt::ZERO ), - FieldElement::from_hex_be( - "0x00da27ef7c3869c3a6cc6a0f7bf07a51c3e590825adba8a51cae27d815839eec" - ) - .unwrap() + Felt::from_hex("0x00da27ef7c3869c3a6cc6a0f7bf07a51c3e590825adba8a51cae27d815839eec") + .unwrap() ) } @@ -433,23 +425,17 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_udc_address_not_unique() { let address = get_udc_deployed_address( - FieldElement::from_hex_be( - "0x06df0e9a9842d97ff3f4c6de7494d6e69d0a107a72150f9c53d59515b91ed9cb", - ) - .unwrap(), - FieldElement::from_hex_be( - "0x0562fc1d911530d18a86ea3ef4be50018923898d3c573288c5abb9c2344459ed", - ) - .unwrap(), + Felt::from_hex("0x06df0e9a9842d97ff3f4c6de7494d6e69d0a107a72150f9c53d59515b91ed9cb") + .unwrap(), + Felt::from_hex("0x0562fc1d911530d18a86ea3ef4be50018923898d3c573288c5abb9c2344459ed") + .unwrap(), &UdcUniqueness::NotUnique, - &[FieldElement::from_hex_be("0x1234").unwrap()], + &[Felt::from_hex("0x1234").unwrap()], ); assert_eq!( - FieldElement::from_hex_be( - "0x0288e5952d2f2f0e897ea0c5401c6e9f584a89eebfb08b5b26f090a8bbf67eb6", - ) - .unwrap(), + Felt::from_hex("0x0288e5952d2f2f0e897ea0c5401c6e9f584a89eebfb08b5b26f090a8bbf67eb6",) + .unwrap(), address ); } @@ -458,32 +444,26 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_udc_address_unique() { let address = get_udc_deployed_address( - FieldElement::from_hex_be( - "0x01f65976b95bf17ae1cb04afc9fc1eeee26d3e1aaa1f30aa535bf261e4322ab8", - ) - .unwrap(), - FieldElement::from_hex_be( - "0x0562fc1d911530d18a86ea3ef4be50018923898d3c573288c5abb9c2344459ed", - ) - .unwrap(), + Felt::from_hex("0x01f65976b95bf17ae1cb04afc9fc1eeee26d3e1aaa1f30aa535bf261e4322ab8") + .unwrap(), + Felt::from_hex("0x0562fc1d911530d18a86ea3ef4be50018923898d3c573288c5abb9c2344459ed") + .unwrap(), &UdcUniqueness::Unique(UdcUniqueSettings { - deployer_address: FieldElement::from_hex_be( + deployer_address: Felt::from_hex( "0x00b1461de04c6a1aa3375bdf9b7723a8779c082ffe21311d683a0b15c078b5dc", ) .unwrap(), - udc_contract_address: FieldElement::from_hex_be( + udc_contract_address: Felt::from_hex( "0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf", ) .unwrap(), }), - &[FieldElement::from_hex_be("0x1234").unwrap()], + &[Felt::from_hex("0x1234").unwrap()], ); assert_eq!( - FieldElement::from_hex_be( - "0x02406943b25942021f213b047c8765e531dddce3b981722f7aeb2ca137e18dbf", - ) - .unwrap(), + Felt::from_hex("0x02406943b25942021f213b047c8765e531dddce3b981722f7aeb2ca137e18dbf",) + .unwrap(), address ); } diff --git a/starknet-crypto-codegen/Cargo.toml b/starknet-crypto-codegen/Cargo.toml index 08c2c067..391080c7 100644 --- a/starknet-crypto-codegen/Cargo.toml +++ b/starknet-crypto-codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-crypto-codegen" -version = "0.3.3" +version = "0.4.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -16,6 +16,9 @@ keywords = ["ethereum", "starknet", "web3", "no_std"] proc-macro = true [dependencies] -starknet-curve = { version = "0.4.2", path = "../starknet-curve" } -starknet-ff = { version = "0.3.7", path = "../starknet-ff", default-features = false } -syn = { version = "2.0.15", default-features = false } +starknet-curve = { version = "0.5.0", path = "../starknet-curve" } +syn = "2.0.55" +starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve"] } + +[lints] +workspace = true diff --git a/starknet-crypto-codegen/src/pedersen.rs b/starknet-crypto-codegen/src/pedersen.rs index 66e5a3bf..ab0cb007 100644 --- a/starknet-crypto-codegen/src/pedersen.rs +++ b/starknet-crypto-codegen/src/pedersen.rs @@ -4,10 +4,8 @@ use std::fmt::Write; use proc_macro::TokenStream; -use starknet_curve::{ - curve_params::{PEDERSEN_P0, PEDERSEN_P1, PEDERSEN_P2, PEDERSEN_P3}, - AffinePoint, -}; +use starknet_curve::curve_params::{PEDERSEN_P0, PEDERSEN_P1, PEDERSEN_P2, PEDERSEN_P3}; +use starknet_types_core::curve::{AffinePoint, ProjectivePoint}; use syn::{parse_macro_input, LitInt}; pub fn lookup_table(input: TokenStream) -> TokenStream { @@ -40,26 +38,26 @@ fn push_points( writeln!( buf, - "pub const CURVE_CONSTS_{name}: [::starknet_curve::AffinePoint; {len}] = [" + "pub const CURVE_CONSTS_{name}: [starknet_types_core::curve::AffinePoint; {len}] = [" )?; let mut bits_left = max_bits; - let mut outer_point = base; + let mut outer_point = ProjectivePoint::from_affine(base.x(), base.y()).unwrap(); while bits_left > 0 { let eat_bits = std::cmp::min(bits_left, bits); let table_size = (1 << eat_bits) - 1; // Loop through each possible bit combination except zero - let mut inner_point = outer_point; + let mut inner_point = outer_point.clone(); for _ in 1..(table_size + 1) { - push_point(buf, &inner_point)?; + push_point(buf, &inner_point.to_affine().unwrap())?; inner_point += &outer_point; } // Shift outer point #bits times bits_left -= eat_bits; for _i in 0..bits { - outer_point.double_assign(); + outer_point += outer_point.clone(); } } @@ -68,22 +66,24 @@ fn push_points( } fn push_point(buf: &mut String, p: &AffinePoint) -> std::fmt::Result { - let x = p.x.into_mont(); - let y = p.y.into_mont(); - writeln!(buf, "::starknet_curve::AffinePoint {{")?; - writeln!(buf, "x: ::starknet_ff::FieldElement::from_mont([")?; + let x = p.x().to_raw(); + let y = p.y().to_raw(); + writeln!( + buf, + "starknet_types_core::curve::AffinePoint::new_unchecked(" + )?; + writeln!(buf, "starknet_types_core::felt::Felt::from_raw([")?; writeln!(buf, "{},", x[0])?; writeln!(buf, "{},", x[1])?; writeln!(buf, "{},", x[2])?; writeln!(buf, "{},", x[3])?; writeln!(buf, "]),")?; - writeln!(buf, "y: ::starknet_ff::FieldElement::from_mont([")?; + writeln!(buf, "starknet_types_core::felt::Felt::from_raw([")?; writeln!(buf, "{},", y[0])?; writeln!(buf, "{},", y[1])?; writeln!(buf, "{},", y[2])?; writeln!(buf, "{},", y[3])?; writeln!(buf, "]),")?; - writeln!(buf, "infinity: false,")?; - writeln!(buf, "}},")?; + writeln!(buf, "),")?; Ok(()) } diff --git a/starknet-crypto-codegen/src/poseidon/mod.rs b/starknet-crypto-codegen/src/poseidon/mod.rs index 7eec0f8b..2a11c2c5 100644 --- a/starknet-crypto-codegen/src/poseidon/mod.rs +++ b/starknet-crypto-codegen/src/poseidon/mod.rs @@ -4,7 +4,7 @@ use std::fmt::Write; use proc_macro::TokenStream; -use starknet_ff::FieldElement; +use starknet_types_core::felt::Felt; mod params; @@ -14,7 +14,7 @@ const PARTIAL_ROUNDS: usize = 83; pub fn poseidon_consts() -> TokenStream { let round_keys = params::RAW_ROUND_KEYS .iter() - .map(|key| key.map(|num| FieldElement::from_dec_str(num).expect("Invalid round key"))) + .map(|key| key.map(|num| Felt::from_dec_str(num).expect("Invalid round key"))) .collect::>(); let flat = round_keys.iter().flatten().cloned().collect::>(); @@ -35,7 +35,7 @@ pub fn poseidon_consts() -> TokenStream { buffer.parse().expect("Invalid code generated") } -pub fn compress_roundkeys(rcs: &[[FieldElement; 3]]) -> Vec { +pub fn compress_roundkeys(rcs: &[[Felt; 3]]) -> Vec { let mut result = Vec::new(); // Add first full rounds @@ -54,11 +54,11 @@ pub fn compress_roundkeys(rcs: &[[FieldElement; 3]]) -> Vec { result } -pub fn compress_roundkeys_partial(rcs: &[[FieldElement; 3]]) -> Vec { +pub fn compress_roundkeys_partial(rcs: &[[Felt; 3]]) -> Vec { let mut result = Vec::new(); let mut idx = FULL_ROUNDS / 2; - let mut state: [FieldElement; 3] = [FieldElement::ZERO; 3]; + let mut state: [Felt; 3] = [Felt::ZERO; 3]; // Add keys for partial rounds for _ in 0..PARTIAL_ROUNDS { @@ -71,13 +71,13 @@ pub fn compress_roundkeys_partial(rcs: &[[FieldElement; 3]]) -> Vec Vec String { +pub fn generate_code(name: &str, rcs: &[Felt]) -> String { let mut buf = String::with_capacity(1024 * 1024); - writeln!(buf, "pub const {}: [FieldElement; {}] = [", name, rcs.len()).unwrap(); + writeln!(buf, "pub const {}: [Felt; {}] = [", name, rcs.len()).unwrap(); rcs.iter().for_each(|num| { writeln!( buf, - "FieldElement::from_mont([{}]),", - num.into_mont().map(|ele| format!("{ele}")).join(",") + "Felt::from_raw([{}]),", + num.to_raw().map(|ele| format!("{ele}")).join(",") ) .unwrap(); }); diff --git a/starknet-crypto/Cargo.toml b/starknet-crypto/Cargo.toml index 8a90ca80..300f9770 100644 --- a/starknet-crypto/Cargo.toml +++ b/starknet-crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-crypto" -version = "0.6.2" +version = "0.7.1" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -14,23 +14,23 @@ keywords = ["ethereum", "starknet", "web3", "no_std"] exclude = ["test-data/**"] [dependencies] -starknet-crypto-codegen = { version = "0.3.3", path = "../starknet-crypto-codegen" } -starknet-curve = { version = "0.4.2", path = "../starknet-curve" } -starknet-ff = { version = "0.3.7", path = "../starknet-ff", default-features = false } +starknet-crypto-codegen = { version = "0.4.0", path = "../starknet-crypto-codegen" } +starknet-curve = { version = "0.5.0", path = "../starknet-curve" } crypto-bigint = { version = "0.5.1", default-features = false, features = ["generic-array", "zeroize"] } hmac = { version = "0.12.1", default-features = false } num-bigint = { version = "0.4.3", default-features = false } num-integer = { version = "0.1.45", default-features = false } -num-traits = { version = "0.2.15", default-features = false } +num-traits = { version = "0.2.18", default-features = false } rfc6979 = { version = "0.4.0", default-features = false } sha2 = { version = "0.10.6", default-features = false } zeroize = { version = "1.6.0", default-features = false } hex = { version = "0.4.3", default-features = false, optional = true } +starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve", "hash"] } [features] default = ["std", "signature-display"] -std = [] -alloc = ["hex?/alloc"] +std = ["starknet-types-core/std"] +alloc = ["hex?/alloc", "starknet-types-core/alloc"] signature-display = ["dep:hex", "alloc"] [dev-dependencies] @@ -39,6 +39,7 @@ hex = "0.4.3" hex-literal = "0.4.1" serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0.96" +starknet-types-core = { version = "0.1.3", default-features = false, features = ["alloc"] } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = "0.3.34" @@ -70,3 +71,6 @@ harness = false [[bench]] name = "rfc6979_generate_k" harness = false + +[lints] +workspace = true diff --git a/starknet-crypto/README.md b/starknet-crypto/README.md index 2715776a..c4790d62 100644 --- a/starknet-crypto/README.md +++ b/starknet-crypto/README.md @@ -14,47 +14,47 @@ If you're a cryptographer, you're welcome to contribute by reviewing the impleme ## Benchmark -These results were generated on the author's machine with _AMD Ryzen 9 5950X 16-Core Processor_ running _Ubuntu 22.04.1 LTS_. +These results were generated on the author's machine with _Apple M3 Max_ running _macOS 14.5_. For instructions on running the benchmarks yourself, check out [this page](../BENCHMARK.md). ### Native ```log -ecdsa_get_public_key time: [125.53 µs 125.63 µs 125.75 µs] -ecdsa_recover time: [421.74 µs 421.93 µs 422.16 µs] -ecdsa_sign time: [170.30 µs 170.50 µs 170.71 µs] -ecdsa_verify time: [428.34 µs 428.73 µs 429.17 µs] -pedersen_hash time: [33.379 µs 33.435 µs 33.521 µs] -poseidon_hash time: [12.552 µs 12.571 µs 12.595 µs] -poseidon_hash_single time: [12.572 µs 12.587 µs 12.601 µs] -poseidon_hash_many time: [25.048 µs 25.089 µs 25.137 µs] -rfc6979_generate_k time: [1.4810 µs 1.4817 µs 1.4827 µs] +ecdsa_get_public_key time: [62.223 µs 62.231 µs 62.240 µs] +ecdsa_recover time: [253.15 µs 253.47 µs 254.13 µs] +ecdsa_sign time: [95.633 µs 95.649 µs 95.668 µs] +ecdsa_verify time: [255.70 µs 255.77 µs 255.84 µs] +pedersen_hash time: [13.021 µs 13.023 µs 13.024 µs] +poseidon_hash time: [5.0139 µs 5.0148 µs 5.0155 µs] +poseidon_hash_single time: [5.0239 µs 5.0381 µs 5.0543 µs] +poseidon_hash_many time: [10.077 µs 10.087 µs 10.100 µs] +rfc6979_generate_k time: [4.5806 µs 4.5821 µs 4.5836 µs] ``` ### WebAssembly -_(With its excellent wasm performance, results are only provided for Node.js here. Check out the [benchmark page](../BENCHMARK.md) for running the benchmark on other runtimes)._ +_(Results are only provided for `wasmtime` here. Check out the [benchmark page](../BENCHMARK.md) for running the benchmark on other runtimes)._ Runtime version: ```console -$ node --version -v18.16.0 +$ wasmtime --version +wasmtime-cli 21.0.1 (cedf9aa0f 2024-05-22) ``` -Node.js results: +`wasmtime` results: ```log -ecdsa_get_public_key time: [1.0093 ms 1.0118 ms 1.0147 ms] -ecdsa_recover time: [3.0610 ms 3.0627 ms 3.0646 ms] -ecdsa_sign time: [1.0584 ms 1.0600 ms 1.0615 ms] -ecdsa_verify time: [3.0273 ms 3.0309 ms 3.0345 ms] -pedersen_hash time: [234.12 µs 234.30 µs 234.49 µs] -poseidon_hash time: [90.892 µs 91.032 µs 91.166 µs] -poseidon_hash_single time: [90.358 µs 90.404 µs 90.451 µs] -poseidon_hash_many time: [180.93 µs 181.13 µs 181.35 µs] -rfc6979_generate_k time: [9.2623 µs 9.2793 µs 9.2979 µs] +ecdsa_get_public_key time: [333.64 µs 334.07 µs 334.48 µs] +ecdsa_recover time: [1.1177 ms 1.1207 ms 1.1248 ms] +ecdsa_sign time: [386.33 µs 387.42 µs 388.68 µs] +ecdsa_verify time: [1.1246 ms 1.1280 ms 1.1320 ms] +pedersen_hash time: [64.934 µs 64.962 µs 64.993 µs] +poseidon_hash time: [20.745 µs 20.772 µs 20.825 µs] +poseidon_hash_single time: [20.790 µs 20.813 µs 20.837 µs] +poseidon_hash_many time: [41.878 µs 41.911 µs 41.945 µs] +rfc6979_generate_k time: [11.564 µs 11.566 µs 11.569 µs] ``` ## Credits diff --git a/starknet-crypto/benches/ecdsa_get_public_key.rs b/starknet-crypto/benches/ecdsa_get_public_key.rs index bbffb15e..77b4149e 100644 --- a/starknet-crypto/benches/ecdsa_get_public_key.rs +++ b/starknet-crypto/benches/ecdsa_get_public_key.rs @@ -1,11 +1,12 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use hex_literal::hex; -use starknet_crypto::{get_public_key, FieldElement}; +use starknet_crypto::get_public_key; +use starknet_types_core::felt::Felt; pub fn criterion_benchmark(c: &mut Criterion) { let private_key = hex!("04a724706e80e5ea88b9ee60a7ede83cbc2de27da0659bef2929381a298b672d"); - let private_key = FieldElement::from_bytes_be(&private_key).unwrap(); + let private_key = Felt::from_bytes_be(&private_key); c.bench_function("ecdsa_get_public_key", |b| { b.iter(|| { diff --git a/starknet-crypto/benches/ecdsa_recover.rs b/starknet-crypto/benches/ecdsa_recover.rs index 598e47cb..a59a852a 100644 --- a/starknet-crypto/benches/ecdsa_recover.rs +++ b/starknet-crypto/benches/ecdsa_recover.rs @@ -1,19 +1,14 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use starknet_crypto::{recover, sign, FieldElement}; +use starknet_crypto::{recover, sign}; +use starknet_types_core::felt::Felt; pub fn criterion_benchmark(c: &mut Criterion) { - let private_key = FieldElement::from_hex_be( - "0000000000000000000000000000000000000000000000000000000000000001", - ) - .unwrap(); - let message = FieldElement::from_hex_be( - "0000000000000000000000000000000000000000000000000000000000000001", - ) - .unwrap(); - let k = FieldElement::from_hex_be( - "0000000000000000000000000000000000000000000000000000000000000001", - ) - .unwrap(); + let private_key = + Felt::from_hex("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); + let message = + Felt::from_hex("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); + let k = + Felt::from_hex("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); let signature = sign(&private_key, &message, &k).unwrap(); diff --git a/starknet-crypto/benches/ecdsa_sign.rs b/starknet-crypto/benches/ecdsa_sign.rs index 67a3cd2e..26351332 100644 --- a/starknet-crypto/benches/ecdsa_sign.rs +++ b/starknet-crypto/benches/ecdsa_sign.rs @@ -1,15 +1,16 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use hex_literal::hex; -use starknet_crypto::{sign, FieldElement}; +use starknet_crypto::sign; +use starknet_types_core::felt::Felt; pub fn criterion_benchmark(c: &mut Criterion) { let private_key = hex!("04a724706e80e5ea88b9ee60a7ede83cbc2de27da0659bef2929381a298b672d"); let message = hex!("010aaf60f545a5b9a55463fbb56f35dfdfe8010ff1d95283afe1b14e07cb8f61"); let k = hex!("075414c392c57a61417fc1702ad6fa83d12541690963915646617b59451972b3"); - let private_key = FieldElement::from_bytes_be(&private_key).unwrap(); - let message = FieldElement::from_bytes_be(&message).unwrap(); - let k = FieldElement::from_bytes_be(&k).unwrap(); + let private_key = Felt::from_bytes_be(&private_key); + let message = Felt::from_bytes_be(&message); + let k = Felt::from_bytes_be(&k); c.bench_function("ecdsa_sign", |b| { b.iter(|| { diff --git a/starknet-crypto/benches/ecdsa_verify.rs b/starknet-crypto/benches/ecdsa_verify.rs index 86f03b9a..744532e7 100644 --- a/starknet-crypto/benches/ecdsa_verify.rs +++ b/starknet-crypto/benches/ecdsa_verify.rs @@ -1,6 +1,7 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use hex_literal::hex; -use starknet_crypto::{verify, FieldElement}; +use starknet_crypto::verify; +use starknet_types_core::felt::Felt; pub fn criterion_benchmark(c: &mut Criterion) { let stark_key = hex!("0565ee8f4203a04fbd5de77c678bc3738538f35c0871e377cdc45fcfa79e6bd9"); @@ -8,10 +9,10 @@ pub fn criterion_benchmark(c: &mut Criterion) { let r_bytes = hex!("03879bf25e6919880960131bb3b614c40d942791f83dac999d28028824c2d712"); let s_bytes = hex!("01f2a4527241c802e0885cf3aeac5bdfdbb559c09a45e1b745addae358f6c03b"); - let stark_key = FieldElement::from_bytes_be(&stark_key).unwrap(); - let msg_hash = FieldElement::from_bytes_be(&msg_hash).unwrap(); - let r_bytes = FieldElement::from_bytes_be(&r_bytes).unwrap(); - let s_bytes = FieldElement::from_bytes_be(&s_bytes).unwrap(); + let stark_key = Felt::from_bytes_be(&stark_key); + let msg_hash = Felt::from_bytes_be(&msg_hash); + let r_bytes = Felt::from_bytes_be(&r_bytes); + let s_bytes = Felt::from_bytes_be(&s_bytes); c.bench_function("ecdsa_verify", |b| { b.iter(|| { diff --git a/starknet-crypto/benches/pedersen_hash.rs b/starknet-crypto/benches/pedersen_hash.rs index d3899037..cc6a3ff1 100644 --- a/starknet-crypto/benches/pedersen_hash.rs +++ b/starknet-crypto/benches/pedersen_hash.rs @@ -1,6 +1,7 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use hex_literal::hex; -use starknet_crypto::{pedersen_hash, FieldElement}; +use starknet_crypto::pedersen_hash; +use starknet_types_core::felt::Felt; // Benchmark taken from pathfinder for performance comparison: // https://github.com/eqlabs/pathfinder/blob/b091cb889e624897dbb0cbec3c1df9a9e411eb1e/crates/pedersen/benches/pedersen.rs @@ -9,8 +10,8 @@ pub fn criterion_benchmark(c: &mut Criterion) { let e0 = hex!("03d937c035c878245caf64531a5756109c53068da139362728feb561405371cb"); let e1 = hex!("0208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a"); - let e0 = FieldElement::from_bytes_be(&e0).unwrap(); - let e1 = FieldElement::from_bytes_be(&e1).unwrap(); + let e0 = Felt::from_bytes_be(&e0); + let e1 = Felt::from_bytes_be(&e1); c.bench_function("pedersen_hash", |b| { b.iter(|| { diff --git a/starknet-crypto/benches/poseidon_hash.rs b/starknet-crypto/benches/poseidon_hash.rs index c81a370f..b43d56e2 100644 --- a/starknet-crypto/benches/poseidon_hash.rs +++ b/starknet-crypto/benches/poseidon_hash.rs @@ -1,15 +1,16 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use hex_literal::hex; -use starknet_crypto::{poseidon_hash, poseidon_hash_many, poseidon_hash_single, FieldElement}; +use starknet_crypto::{poseidon_hash, poseidon_hash_many, poseidon_hash_single}; +use starknet_types_core::felt::Felt; pub fn criterion_benchmark(c: &mut Criterion) { let e0 = hex!("03d937c035c878245caf64531a5756109c53068da139362728feb561405371cb"); let e1 = hex!("0208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a"); let e2 = hex!("013126bb6143939a9da42c90ce6f4a48f8430f9955a62367571a348e9c65177c"); - let e0 = FieldElement::from_bytes_be(&e0).unwrap(); - let e1 = FieldElement::from_bytes_be(&e1).unwrap(); - let e2 = FieldElement::from_bytes_be(&e2).unwrap(); + let e0 = Felt::from_bytes_be(&e0); + let e1 = Felt::from_bytes_be(&e1); + let e2 = Felt::from_bytes_be(&e2); c.bench_function("poseidon_hash", |b| { b.iter(|| { diff --git a/starknet-crypto/benches/rfc6979_generate_k.rs b/starknet-crypto/benches/rfc6979_generate_k.rs index e28c28e7..ddcb93cc 100644 --- a/starknet-crypto/benches/rfc6979_generate_k.rs +++ b/starknet-crypto/benches/rfc6979_generate_k.rs @@ -1,15 +1,16 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use hex_literal::hex; -use starknet_crypto::{rfc6979_generate_k, FieldElement}; +use starknet_crypto::rfc6979_generate_k; +use starknet_types_core::felt::Felt; pub fn criterion_benchmark(c: &mut Criterion) { let message_hash = hex!("010b559a3b4dc1b7137d90521cb413b397ff07963214d128a92d65aec7182f68"); let private_key = hex!("07e3184f4bef18f371bc53fc412dff1b30dbc94f758490fb8e2349bae647a642"); let seed = hex!("03fe27199aaad4e700559e2436a919f4de70def585a6deb2f4c087fdf6a27c1b"); - let message_hash = FieldElement::from_bytes_be(&message_hash).unwrap(); - let private_key = FieldElement::from_bytes_be(&private_key).unwrap(); - let seed = FieldElement::from_bytes_be(&seed).unwrap(); + let message_hash = Felt::from_bytes_be(&message_hash); + let private_key = Felt::from_bytes_be(&private_key); + let seed = Felt::from_bytes_be(&seed); c.bench_function("rfc6979_generate_k", |b| { b.iter(|| { diff --git a/starknet-crypto/src/ecdsa.rs b/starknet-crypto/src/ecdsa.rs index 38673941..ae15e181 100644 --- a/starknet-crypto/src/ecdsa.rs +++ b/starknet-crypto/src/ecdsa.rs @@ -1,38 +1,37 @@ -use starknet_curve::{ - curve_params::{EC_ORDER, GENERATOR}, - AffinePoint, ProjectivePoint, -}; +use starknet_curve::curve_params::{ALPHA, BETA, EC_ORDER, GENERATOR}; use crate::{ fe_utils::{add_unbounded, bigint_mul_mod_floor, mod_inverse, mul_mod_floor}, - FieldElement, RecoverError, SignError, VerifyError, + RecoverError, SignError, VerifyError, }; +use starknet_types_core::curve::{AffinePoint, ProjectivePoint}; +use starknet_types_core::felt::Felt; -const ELEMENT_UPPER_BOUND: FieldElement = FieldElement::from_mont([ - 18446743986131435553, - 160989183, - 18446744073709255680, +const ELEMENT_UPPER_BOUND: Felt = Felt::from_raw([ 576459263475450960, + 18446744073709255680, + 160989183, + 18446743986131435553, ]); /// Stark ECDSA signature #[derive(Debug)] pub struct Signature { /// The `r` value of a signature - pub r: FieldElement, + pub r: Felt, /// The `s` value of a signature - pub s: FieldElement, + pub s: Felt, } /// Stark ECDSA signature with `v` #[derive(Debug)] pub struct ExtendedSignature { /// The `r` value of a signature - pub r: FieldElement, + pub r: Felt, /// The `s` value of a signature - pub s: FieldElement, + pub s: Felt, /// The `v` value of a signature - pub v: FieldElement, + pub v: Felt, } impl From for Signature { @@ -46,7 +45,7 @@ impl From for Signature { #[cfg(feature = "signature-display")] impl core::fmt::Display for Signature { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, "{}{}", @@ -58,7 +57,7 @@ impl core::fmt::Display for Signature { #[cfg(feature = "signature-display")] impl core::fmt::Display for ExtendedSignature { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, "{}{}{:02x}", @@ -74,8 +73,11 @@ impl core::fmt::Display for ExtendedSignature { /// ### Arguments /// /// * `private_key`: The private key -pub fn get_public_key(private_key: &FieldElement) -> FieldElement { - mul_by_bits(&GENERATOR, private_key).x +pub fn get_public_key(private_key: &Felt) -> Felt { + mul_by_bits(&GENERATOR, private_key) + .to_affine() + .unwrap() + .x() } /// Computes ECDSA signature given a Stark private key and message hash. @@ -85,21 +87,17 @@ pub fn get_public_key(private_key: &FieldElement) -> FieldElement { /// * `private_key`: The private key /// * `message`: The message hash /// * `k`: A random `k` value. You **MUST NOT** use the same `k` on different signatures -pub fn sign( - private_key: &FieldElement, - message: &FieldElement, - k: &FieldElement, -) -> Result { +pub fn sign(private_key: &Felt, message: &Felt, k: &Felt) -> Result { if message >= &ELEMENT_UPPER_BOUND { return Err(SignError::InvalidMessageHash); } - if k == &FieldElement::ZERO { + if k == &Felt::ZERO { return Err(SignError::InvalidK); } - let full_r = mul_by_bits(&GENERATOR, k); - let r = full_r.x; - if r == FieldElement::ZERO || r >= ELEMENT_UPPER_BOUND { + let full_r = mul_by_bits(&GENERATOR, k).to_affine().unwrap(); + let r = full_r.x(); + if r == Felt::ZERO || r >= ELEMENT_UPPER_BOUND { return Err(SignError::InvalidK); } @@ -108,13 +106,15 @@ pub fn sign( let s = mul_mod_floor(&r, private_key, &EC_ORDER); let s = add_unbounded(&s, message); let s = bigint_mul_mod_floor(s, &k_inv, &EC_ORDER); - if s == FieldElement::ZERO || s >= ELEMENT_UPPER_BOUND { + if s == Felt::ZERO || s >= ELEMENT_UPPER_BOUND { return Err(SignError::InvalidK); } - let v = full_r.y & FieldElement::ONE; - - Ok(ExtendedSignature { r, s, v }) + Ok(ExtendedSignature { + r, + s, + v: (full_r.y().to_bigint() & Felt::ONE.to_bigint()).into(), + }) } /// Verifies if a signature is valid over a message hash given a public key. Returns an error @@ -126,29 +126,27 @@ pub fn sign( /// * `message`: The message hash /// * `r`: The `r` value of the signature /// * `s`: The `s` value of the signature -pub fn verify( - public_key: &FieldElement, - message: &FieldElement, - r: &FieldElement, - s: &FieldElement, -) -> Result { +pub fn verify(public_key: &Felt, message: &Felt, r: &Felt, s: &Felt) -> Result { if message >= &ELEMENT_UPPER_BOUND { return Err(VerifyError::InvalidMessageHash); } - if r == &FieldElement::ZERO || r >= &ELEMENT_UPPER_BOUND { + if r == &Felt::ZERO || r >= &ELEMENT_UPPER_BOUND { return Err(VerifyError::InvalidR); } - if s == &FieldElement::ZERO || s >= &ELEMENT_UPPER_BOUND { + if s == &Felt::ZERO || s >= &ELEMENT_UPPER_BOUND { return Err(VerifyError::InvalidS); } - let full_public_key = match AffinePoint::from_x(*public_key) { - Some(value) => value, - None => return Err(VerifyError::InvalidPublicKey), - }; + let full_public_key = AffinePoint::new( + *public_key, + (public_key.square() * public_key + ALPHA * public_key + BETA) + .sqrt() + .ok_or(VerifyError::InvalidPublicKey)?, + ) + .unwrap(); let w = mod_inverse(s, &EC_ORDER); - if w == FieldElement::ZERO || w >= ELEMENT_UPPER_BOUND { + if w == Felt::ZERO || w >= ELEMENT_UPPER_BOUND { return Err(VerifyError::InvalidS); } @@ -158,7 +156,8 @@ pub fn verify( let rw = mul_mod_floor(r, &w, &EC_ORDER); let rw_q = mul_by_bits(&full_public_key, &rw); - Ok((&zw_g + &rw_q).x == *r || (&zw_g - &rw_q).x == *r) + Ok((&zw_g + &rw_q).to_affine().unwrap().x() == *r + || (&zw_g - &rw_q).to_affine().unwrap().x() == *r) } /// Recovers the public key from a message and (r, s, v) signature parameters @@ -169,47 +168,61 @@ pub fn verify( /// * `r_bytes`: The `r` value of the signature /// * `s_bytes`: The `s` value of the signature /// * `v_bytes`: The `v` value of the signature -pub fn recover( - message: &FieldElement, - r: &FieldElement, - s: &FieldElement, - v: &FieldElement, -) -> Result { +pub fn recover(message: &Felt, r: &Felt, s: &Felt, v: &Felt) -> Result { if message >= &ELEMENT_UPPER_BOUND { return Err(RecoverError::InvalidMessageHash); } - if r == &FieldElement::ZERO || r >= &ELEMENT_UPPER_BOUND { + if r == &Felt::ZERO || r >= &ELEMENT_UPPER_BOUND { return Err(RecoverError::InvalidR); } - if s == &FieldElement::ZERO || s >= &EC_ORDER { + if s == &Felt::ZERO || s >= &EC_ORDER { return Err(RecoverError::InvalidS); } - if v > &FieldElement::ONE { + if v > &Felt::ONE { return Err(RecoverError::InvalidV); } - let mut full_r = AffinePoint::from_x(*r).ok_or(RecoverError::InvalidR)?; - if (full_r.y & FieldElement::ONE) != *v { - full_r.y = -full_r.y; + let full_r = AffinePoint::new( + *r, + (r * r * r + ALPHA * r + BETA) + .sqrt() + .ok_or(RecoverError::InvalidR)?, + ) + .unwrap(); + + let mut full_r_y = full_r.y(); + + let mut bits = [false; 256]; + + for (i, (&a, &b)) in full_r + .y() + .to_bits_le() + .iter() + .zip(Felt::ONE.to_bits_le().iter()) + .enumerate() + { + bits[i] = a && b; } - let full_rs = mul_by_bits(&full_r, s); + + if bits != v.to_bits_le() { + full_r_y = -full_r.y(); + } + + let full_rs = mul_by_bits(&AffinePoint::new(full_r.x(), full_r_y).unwrap(), s); let zg = mul_by_bits(&GENERATOR, message); let r_inv = mod_inverse(r, &EC_ORDER); let rs_zg = &full_rs - &zg; - let k = mul_by_bits(&rs_zg, &r_inv); + let k = mul_by_bits(&rs_zg.to_affine().unwrap(), &r_inv); - Ok(k.x) + Ok(k.to_affine().unwrap().x()) } #[inline(always)] -fn mul_by_bits(x: &AffinePoint, y: &FieldElement) -> AffinePoint { - let x = ProjectivePoint::from_affine_point(x); - let y = y.to_bits_le(); - let z = &x * &y; - AffinePoint::from(&z) +fn mul_by_bits(x: &AffinePoint, y: &Felt) -> ProjectivePoint { + &ProjectivePoint::from_affine(x.x(), x.y()).unwrap() * *y } #[cfg(test)] @@ -265,7 +278,7 @@ mod tests { serde_json::from_str(json_data).expect("Unable to parse the JSON"); // Iterating over each element in the JSON - for (private_key, expected_public_key) in key_map.into_iter() { + for (private_key, expected_public_key) in key_map { let private_key = if private_key.len() % 2 != 0 { format!("0{}", private_key.trim_start_matches("0x")) } else { diff --git a/starknet-crypto/src/fe_utils.rs b/starknet-crypto/src/fe_utils.rs index 7fe285c6..6efa5ce7 100644 --- a/starknet-crypto/src/fe_utils.rs +++ b/starknet-crypto/src/fe_utils.rs @@ -4,33 +4,25 @@ use num_bigint::BigInt; use num_integer::Integer; use num_traits::{One, Zero}; -use crate::FieldElement; +use starknet_types_core::felt::Felt; // These are inefficient and crappy implementations of crypto math operations because I have // absolutely no idea how to do them without using `num-bigint`. But hey it works!!! // // Contributions are welcome. Please help us get rid of this junk :) -pub fn add_unbounded(augend: &FieldElement, addend: &FieldElement) -> BigInt { +pub fn add_unbounded(augend: &Felt, addend: &Felt) -> BigInt { let augend = BigInt::from_bytes_be(num_bigint::Sign::Plus, &augend.to_bytes_be()); let addend = BigInt::from_bytes_be(num_bigint::Sign::Plus, &addend.to_bytes_be()); augend.add(addend) } -pub fn mul_mod_floor( - multiplicand: &FieldElement, - multiplier: &FieldElement, - modulus: &FieldElement, -) -> FieldElement { +pub fn mul_mod_floor(multiplicand: &Felt, multiplier: &Felt, modulus: &Felt) -> Felt { let multiplicand = BigInt::from_bytes_be(num_bigint::Sign::Plus, &multiplicand.to_bytes_be()); bigint_mul_mod_floor(multiplicand, multiplier, modulus) } -pub fn bigint_mul_mod_floor( - multiplicand: BigInt, - multiplier: &FieldElement, - modulus: &FieldElement, -) -> FieldElement { +pub fn bigint_mul_mod_floor(multiplicand: BigInt, multiplier: &Felt, modulus: &Felt) -> Felt { let multiplier = BigInt::from_bytes_be(num_bigint::Sign::Plus, &multiplier.to_bytes_be()); let modulus = BigInt::from_bytes_be(num_bigint::Sign::Plus, &modulus.to_bytes_be()); @@ -40,10 +32,10 @@ pub fn bigint_mul_mod_floor( let mut result = [0u8; 32]; result[(32 - buffer.len())..].copy_from_slice(&buffer[..]); - FieldElement::from_bytes_be(&result).unwrap() + Felt::from_bytes_be(&result) } -pub fn mod_inverse(operand: &FieldElement, modulus: &FieldElement) -> FieldElement { +pub fn mod_inverse(operand: &Felt, modulus: &Felt) -> Felt { let operand = BigInt::from_bytes_be(num_bigint::Sign::Plus, &operand.to_bytes_be()); let modulus = BigInt::from_bytes_be(num_bigint::Sign::Plus, &modulus.to_bytes_be()); @@ -63,5 +55,5 @@ pub fn mod_inverse(operand: &FieldElement, modulus: &FieldElement) -> FieldEleme let mut result = [0u8; 32]; result[(32 - buffer.len())..].copy_from_slice(&buffer[..]); - FieldElement::from_bytes_be(&result).unwrap() + Felt::from_bytes_be(&result) } diff --git a/starknet-crypto/src/lib.rs b/starknet-crypto/src/lib.rs index 2dd3182f..47b7db8b 100644 --- a/starknet-crypto/src/lib.rs +++ b/starknet-crypto/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![doc = include_str!("../README.md")] +#[allow(unused_extern_crates)] #[cfg(all(not(feature = "std"), any(test, feature = "alloc")))] extern crate alloc; @@ -15,7 +16,7 @@ mod rfc6979; #[cfg(test)] mod test_utils; -pub use starknet_ff::FieldElement; +pub use starknet_types_core::felt::Felt; pub use pedersen_hash::pedersen_hash; diff --git a/starknet-crypto/src/pedersen_hash.rs b/starknet-crypto/src/pedersen_hash.rs index 87ab7ca8..5080a826 100644 --- a/starknet-crypto/src/pedersen_hash.rs +++ b/starknet-crypto/src/pedersen_hash.rs @@ -1,9 +1,7 @@ -use starknet_curve::{curve_params, AffinePoint, ProjectivePoint}; -use starknet_ff::FieldElement; - -use crate::pedersen_points::*; - -const SHIFT_POINT: ProjectivePoint = ProjectivePoint::from_affine_point(&curve_params::SHIFT_POINT); +use starknet_types_core::{ + felt::Felt, + hash::{Pedersen, StarkHash}, +}; /// Computes the Starkware version of the Pedersen hash of x and y. All inputs are little-endian. /// @@ -11,37 +9,8 @@ const SHIFT_POINT: ProjectivePoint = ProjectivePoint::from_affine_point(&curve_p /// /// * `x`: The x coordinate /// * `y`: The y coordinate -pub fn pedersen_hash(x: &FieldElement, y: &FieldElement) -> FieldElement { - let x = x.to_bits_le(); - let y = y.to_bits_le(); - - // Preprocessed material is lookup-tables for each chunk of bits - let table_size = (1 << CURVE_CONSTS_BITS) - 1; - let add_points = |acc: &mut ProjectivePoint, bits: &[bool], prep: &[AffinePoint]| { - bits.chunks(CURVE_CONSTS_BITS) - .enumerate() - .for_each(|(i, v)| { - let offset = v - .iter() - .rev() - .fold(0, |acc, &bit| (acc << 1) + bit as usize); - - if offset > 0 { - // Table lookup at 'offset-1' in table for chunk 'i' - *acc += &prep[i * table_size + offset - 1]; - } - }); - }; - - // Compute hash - let mut acc = SHIFT_POINT; - add_points(&mut acc, &x[..248], &CURVE_CONSTS_P0); // Add a_low * P1 - add_points(&mut acc, &x[248..252], &CURVE_CONSTS_P1); // Add a_high * P2 - add_points(&mut acc, &y[..248], &CURVE_CONSTS_P2); // Add b_low * P3 - add_points(&mut acc, &y[248..252], &CURVE_CONSTS_P3); // Add b_high * P4 - - // Return x-coordinate - AffinePoint::from(&acc).x +pub fn pedersen_hash(x: &Felt, y: &Felt) -> Felt { + Pedersen::hash(x, y) } #[cfg(test)] @@ -68,7 +37,7 @@ mod tests { ), ]; - for (in1, in2, expected_hash) in test_data.into_iter() { + for (in1, in2, expected_hash) in test_data { let in1 = field_element_from_be_hex(in1); let in2 = field_element_from_be_hex(in2); let expected_hash = field_element_from_be_hex(expected_hash); diff --git a/starknet-crypto/src/poseidon_hash.rs b/starknet-crypto/src/poseidon_hash.rs index 235cc829..ff96efbb 100644 --- a/starknet-crypto/src/poseidon_hash.rs +++ b/starknet-crypto/src/poseidon_hash.rs @@ -2,27 +2,27 @@ // https://github.com/eqlabs/pathfinder/blob/00a1a74a90a7b8a7f1d07ac3e616be1cb39cf8f1/crates/stark_poseidon/src/lib.rs use starknet_crypto_codegen::poseidon_consts; -use starknet_ff::FieldElement; +use starknet_types_core::felt::Felt; poseidon_consts!(); /// A hasher for Starknet Poseidon hash. /// -/// Using this hasher is the same as calling [poseidon_hash_many]. +/// Using this hasher is the same as calling [`poseidon_hash_many`]. #[derive(Debug, Default)] pub struct PoseidonHasher { - state: [FieldElement; 3], - buffer: Option, + state: [Felt; 3], + buffer: Option, } impl PoseidonHasher { - /// Creates a new [PoseidonHasher]. + /// Creates a new [`PoseidonHasher`]. pub fn new() -> Self { Self::default() } /// Absorbs message into the hash. - pub fn update(&mut self, msg: FieldElement) { + pub fn update(&mut self, msg: Felt) { match self.buffer.take() { Some(previous_message) => { self.state[0] += previous_message; @@ -36,15 +36,15 @@ impl PoseidonHasher { } /// Finishes and returns hash. - pub fn finalize(mut self) -> FieldElement { + pub fn finalize(mut self) -> Felt { // Applies padding match self.buffer.take() { Some(last_message) => { self.state[0] += last_message; - self.state[1] += FieldElement::ONE; + self.state[1] += Felt::ONE; } None => { - self.state[0] += FieldElement::ONE; + self.state[0] += Felt::ONE; } } poseidon_permute_comp(&mut self.state); @@ -54,45 +54,54 @@ impl PoseidonHasher { } /// Computes the Starknet Poseidon hash of x and y. -pub fn poseidon_hash(x: FieldElement, y: FieldElement) -> FieldElement { - let mut state = [x, y, FieldElement::TWO]; +pub fn poseidon_hash(x: Felt, y: Felt) -> Felt { + let mut state = [x, y, Felt::TWO]; poseidon_permute_comp(&mut state); state[0] } -/// Computes the Starknet Poseidon hash of a single [FieldElement]. -pub fn poseidon_hash_single(x: FieldElement) -> FieldElement { - let mut state = [x, FieldElement::ZERO, FieldElement::ONE]; +/// Computes the Starknet Poseidon hash of a single [`Felt`]. +pub fn poseidon_hash_single(x: Felt) -> Felt { + let mut state = [x, Felt::ZERO, Felt::ONE]; poseidon_permute_comp(&mut state); state[0] } -/// Computes the Starknet Poseidon hash of an arbitrary number of [FieldElement]s. +/// Computes the Starknet Poseidon hash of an arbitrary number of [`Felt`]s. /// -/// Using this function is the same as using [PoseidonHasher]. -pub fn poseidon_hash_many(msgs: &[FieldElement]) -> FieldElement { - let mut state = [FieldElement::ZERO, FieldElement::ZERO, FieldElement::ZERO]; - let mut iter = msgs.chunks_exact(2); +/// Using this function is the same as using [`PoseidonHasher`]. +pub fn poseidon_hash_many<'a, I: IntoIterator>(msgs: I) -> Felt { + let mut state = [Felt::ZERO, Felt::ZERO, Felt::ZERO]; + let mut iter = msgs.into_iter(); + + loop { + match iter.next() { + Some(v) => state[0] += *v, + None => { + state[0] += Felt::ONE; + break; + } + } + + match iter.next() { + Some(v) => state[1] += *v, + None => { + state[1] += Felt::ONE; + break; + } + } - for msg in iter.by_ref() { - state[0] += msg[0]; - state[1] += msg[1]; poseidon_permute_comp(&mut state); } - let r = iter.remainder(); - if r.len() == 1 { - state[0] += r[0]; - } - state[r.len()] += FieldElement::ONE; poseidon_permute_comp(&mut state); state[0] } /// Poseidon permutation function. -pub fn poseidon_permute_comp(state: &mut [FieldElement; 3]) { +pub fn poseidon_permute_comp(state: &mut [Felt; 3]) { let mut idx = 0; // Full rounds @@ -117,26 +126,25 @@ pub fn poseidon_permute_comp(state: &mut [FieldElement; 3]) { /// Linear layer for MDS matrix M = ((3,1,1), (1,-1,1), (1,1,2)) /// Given state vector x, it returns Mx, optimized by precomputing t. #[inline(always)] -fn mix(state: &mut [FieldElement; 3]) { +fn mix(state: &mut [Felt; 3]) { let t = state[0] + state[1] + state[2]; state[0] = t + state[0].double(); state[1] = t - state[1].double(); - state[2] = t - FieldElement::THREE * state[2]; + state[2] = t - Felt::THREE * state[2]; } #[inline] -fn round_comp(state: &mut [FieldElement; 3], idx: usize, full: bool) { +fn round_comp(state: &mut [Felt; 3], idx: usize, full: bool) { if full { state[0] += POSEIDON_COMP_CONSTS[idx]; state[1] += POSEIDON_COMP_CONSTS[idx + 1]; state[2] += POSEIDON_COMP_CONSTS[idx + 2]; state[0] = state[0] * state[0] * state[0]; state[1] = state[1] * state[1] * state[1]; - state[2] = state[2] * state[2] * state[2]; } else { state[2] += POSEIDON_COMP_CONSTS[idx]; - state[2] = state[2] * state[2] * state[2]; } + state[2] = state[2] * state[2] * state[2]; mix(state); } @@ -150,36 +158,24 @@ mod tests { // Test data generated from `cairo-lang` v0.11.0 let test_data = [ ( - FieldElement::from_hex_be( - "0xb662f9017fa7956fd70e26129b1833e10ad000fd37b4d9f4e0ce6884b7bbe", - ) - .unwrap(), - FieldElement::from_hex_be( - "0x1fe356bf76102cdae1bfbdc173602ead228b12904c00dad9cf16e035468bea", - ) - .unwrap(), - FieldElement::from_hex_be( - "0x75540825a6ecc5dc7d7c2f5f868164182742227f1367d66c43ee51ec7937a81", - ) - .unwrap(), + Felt::from_hex("0xb662f9017fa7956fd70e26129b1833e10ad000fd37b4d9f4e0ce6884b7bbe") + .unwrap(), + Felt::from_hex("0x1fe356bf76102cdae1bfbdc173602ead228b12904c00dad9cf16e035468bea") + .unwrap(), + Felt::from_hex("0x75540825a6ecc5dc7d7c2f5f868164182742227f1367d66c43ee51ec7937a81") + .unwrap(), ), ( - FieldElement::from_hex_be( - "0xf4e01b2032298f86b539e3d3ac05ced20d2ef275273f9325f8827717156529", - ) - .unwrap(), - FieldElement::from_hex_be( - "0x587bc46f5f58e0511b93c31134652a689d761a9e7f234f0f130c52e4679f3a", - ) - .unwrap(), - FieldElement::from_hex_be( - "0xbdb3180fdcfd6d6f172beb401af54dd71b6569e6061767234db2b777adf98b", - ) - .unwrap(), + Felt::from_hex("0xf4e01b2032298f86b539e3d3ac05ced20d2ef275273f9325f8827717156529") + .unwrap(), + Felt::from_hex("0x587bc46f5f58e0511b93c31134652a689d761a9e7f234f0f130c52e4679f3a") + .unwrap(), + Felt::from_hex("0xbdb3180fdcfd6d6f172beb401af54dd71b6569e6061767234db2b777adf98b") + .unwrap(), ), ]; - for (x, y, hash) in test_data.into_iter() { + for (x, y, hash) in test_data { assert_eq!(poseidon_hash(x, y), hash); } } @@ -190,28 +186,20 @@ mod tests { // Test data generated from `cairo-lang` v0.11.0 let test_data = [ ( - FieldElement::from_hex_be( - "0x9dad5d6f502ccbcb6d34ede04f0337df3b98936aaf782f4cc07d147e3a4fd6", - ) - .unwrap(), - FieldElement::from_hex_be( - "0x11222854783f17f1c580ff64671bc3868de034c236f956216e8ed4ab7533455", - ) - .unwrap(), + Felt::from_hex("0x9dad5d6f502ccbcb6d34ede04f0337df3b98936aaf782f4cc07d147e3a4fd6") + .unwrap(), + Felt::from_hex("0x11222854783f17f1c580ff64671bc3868de034c236f956216e8ed4ab7533455") + .unwrap(), ), ( - FieldElement::from_hex_be( - "0x3164a8e2181ff7b83391b4a86bc8967f145c38f10f35fc74e9359a0c78f7b6", - ) - .unwrap(), - FieldElement::from_hex_be( - "0x79ad7aa7b98d47705446fa01865942119026ac748d67a5840f06948bce2306b", - ) - .unwrap(), + Felt::from_hex("0x3164a8e2181ff7b83391b4a86bc8967f145c38f10f35fc74e9359a0c78f7b6") + .unwrap(), + Felt::from_hex("0x79ad7aa7b98d47705446fa01865942119026ac748d67a5840f06948bce2306b") + .unwrap(), ), ]; - for (x, hash) in test_data.into_iter() { + for (x, hash) in test_data { assert_eq!(poseidon_hash_single(x), hash); } } @@ -223,51 +211,47 @@ mod tests { let test_data = [ ( vec![ - FieldElement::from_hex_be( + Felt::from_hex( "0x9bf52404586087391c5fbb42538692e7ca2149bac13c145ae4230a51a6fc47", ) .unwrap(), - FieldElement::from_hex_be( + Felt::from_hex( "0x40304159ee9d2d611120fbd7c7fb8020cc8f7a599bfa108e0e085222b862c0", ) .unwrap(), - FieldElement::from_hex_be( + Felt::from_hex( "0x46286e4f3c450761d960d6a151a9c0988f9e16f8a48d4c0a85817c009f806a", ) .unwrap(), ], - FieldElement::from_hex_be( - "0x1ec38b38dc88bac7b0ed6ff6326f975a06a59ac601b417745fd412a5d38e4f7", - ) - .unwrap(), + Felt::from_hex("0x1ec38b38dc88bac7b0ed6ff6326f975a06a59ac601b417745fd412a5d38e4f7") + .unwrap(), ), ( vec![ - FieldElement::from_hex_be( + Felt::from_hex( "0xbdace8883922662601b2fd197bb660b081fcf383ede60725bd080d4b5f2fd3", ) .unwrap(), - FieldElement::from_hex_be( + Felt::from_hex( "0x1eb1daaf3fdad326b959dec70ced23649cdf8786537cee0c5758a1a4229097", ) .unwrap(), - FieldElement::from_hex_be( + Felt::from_hex( "0x869ca04071b779d6f940cdf33e62d51521e19223ab148ef571856ff3a44ff1", ) .unwrap(), - FieldElement::from_hex_be( + Felt::from_hex( "0x533e6df8d7c4b634b1f27035c8676a7439c635e1fea356484de7f0de677930", ) .unwrap(), ], - FieldElement::from_hex_be( - "0x2520b8f910174c3e650725baacad4efafaae7623c69a0b5513d75e500f36624", - ) - .unwrap(), + Felt::from_hex("0x2520b8f910174c3e650725baacad4efafaae7623c69a0b5513d75e500f36624") + .unwrap(), ), ]; - for (input, hash) in test_data.into_iter() { + for (input, hash) in test_data { // Direct function call assert_eq!(poseidon_hash_many(&input), hash); diff --git a/starknet-crypto/src/rfc6979.rs b/starknet-crypto/src/rfc6979.rs index 5b2f5f60..cd7ea7da 100644 --- a/starknet-crypto/src/rfc6979.rs +++ b/starknet-crypto/src/rfc6979.rs @@ -1,10 +1,9 @@ use crypto_bigint::{ArrayEncoding, ByteArray, Integer, U256}; use hmac::digest::Digest; use sha2::digest::{crypto_common::BlockSizeUser, FixedOutputReset, HashMarker}; +use starknet_types_core::felt::Felt; use zeroize::{Zeroize, Zeroizing}; -use crate::FieldElement; - const EC_ORDER: U256 = U256::from_be_hex("0800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f"); @@ -15,11 +14,7 @@ const EC_ORDER: U256 = /// * `message_hash`: message hash /// * `private_key`: private key /// * `seed`: extra seed for additional entropy -pub fn generate_k( - message_hash: &FieldElement, - private_key: &FieldElement, - seed: Option<&FieldElement>, -) -> FieldElement { +pub fn generate_k(message_hash: &Felt, private_key: &Felt, seed: Option<&Felt>) -> Felt { // The message hash padding as implemented in `cairo-lang` is not needed here. The hash is // padded in `cairo-lang` only to make sure the lowest 4 bits won't get truncated, but here it's // never getting truncated anyways. @@ -49,7 +44,7 @@ pub fn generate_k( let mut buffer = [0u8; 32]; buffer[..].copy_from_slice(&k.to_be_byte_array()[..]); - FieldElement::from_bytes_be(&buffer).unwrap() + Felt::from_bytes_be(&buffer) } // Modified from upstream `rfc6979::generate_k` with a hard-coded right bit shift. The more @@ -109,9 +104,9 @@ mod tests { } fn test_generate_k_from_json_str(json_str: &'static str) { - let test_vectors: Vec = serde_json::from_str(json_str).unwrap(); + let test_vectors: Vec> = serde_json::from_str(json_str).unwrap(); - for test_vector in test_vectors.iter() { + for test_vector in &test_vectors { let msg_hash = field_element_from_be_hex(test_vector.msg_hash); let priv_key = field_element_from_be_hex(test_vector.priv_key); let seed = field_element_from_be_hex(test_vector.seed); diff --git a/starknet-crypto/src/test_utils.rs b/starknet-crypto/src/test_utils.rs index cbe0f8ef..b1e36f14 100644 --- a/starknet-crypto/src/test_utils.rs +++ b/starknet-crypto/src/test_utils.rs @@ -1,6 +1,6 @@ -use crate::FieldElement; +use starknet_types_core::felt::Felt; -pub fn field_element_from_be_hex(hex: &str) -> FieldElement { +pub fn field_element_from_be_hex(hex: &str) -> Felt { let decoded = hex::decode(hex.trim_start_matches("0x")).unwrap(); if decoded.len() > 32 { @@ -10,5 +10,5 @@ pub fn field_element_from_be_hex(hex: &str) -> FieldElement { let mut buffer = [0u8; 32]; buffer[(32 - decoded.len())..].copy_from_slice(&decoded[..]); - FieldElement::from_bytes_be(&buffer).unwrap() + Felt::from_bytes_be(&buffer) } diff --git a/starknet-curve/Cargo.toml b/starknet-curve/Cargo.toml index ed60a50d..7c01748b 100644 --- a/starknet-curve/Cargo.toml +++ b/starknet-curve/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-curve" -version = "0.4.2" +version = "0.5.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -13,4 +13,7 @@ Stark curve keywords = ["ethereum", "starknet", "web3", "no_std"] [dependencies] -starknet-ff = { version = "0.3.7", path = "../starknet-ff", default-features = false } +starknet-types-core = { version = "0.1.3", default-features = false, features = ["curve"] } + +[lints] +workspace = true diff --git a/starknet-curve/src/curve_params.rs b/starknet-curve/src/curve_params.rs index c9938f7f..5368cbc4 100644 --- a/starknet-curve/src/curve_params.rs +++ b/starknet-curve/src/curve_params.rs @@ -1,116 +1,113 @@ -use starknet_ff::FieldElement; +use starknet_types_core::curve::AffinePoint; +use starknet_types_core::felt::Felt; -use crate::ec_point::AffinePoint; - -pub const EC_ORDER: FieldElement = FieldElement::from_mont([ - 8939893405601011193, - 1143265896874747514, - 9, +pub const EC_ORDER: Felt = Felt::from_raw([ 369010039416812937, + 9, + 1143265896874747514, + 8939893405601011193, ]); -pub const ALPHA: FieldElement = FieldElement::from_mont([ - 18446744073709551585, +pub const ALPHA: Felt = Felt::from_raw([ + 576460752303422960, 18446744073709551615, 18446744073709551615, - 576460752303422960, + 18446744073709551585, ]); -pub const BETA: FieldElement = FieldElement::from_mont([ - 3863487492851900874, - 7432612994240712710, - 12360725113329547591, +pub const BETA: Felt = Felt::from_raw([ 88155977965380735, + 12360725113329547591, + 7432612994240712710, + 3863487492851900874, ]); -pub const GENERATOR: AffinePoint = AffinePoint { - x: FieldElement::from_mont([ - 14484022957141291997, - 5884444832209845738, - 299981207024966779, +pub const GENERATOR: AffinePoint = AffinePoint::new_unchecked( + Felt::from_raw([ 232005955912912577, + 299981207024966779, + 5884444832209845738, + 14484022957141291997, ]), - y: FieldElement::from_mont([ - 6241159653446987914, - 664812301889158119, - 18147424675297964973, + Felt::from_raw([ 405578048423154473, + 18147424675297964973, + 664812301889158119, + 6241159653446987914, ]), - infinity: false, -}; +); -pub const SHIFT_POINT: AffinePoint = AffinePoint { - x: FieldElement::from_mont([ - 1933903796324928314, - 7739989395386261137, - 1641324389046377921, +pub const SHIFT_POINT: AffinePoint = AffinePoint::new_unchecked( + Felt::from_raw([ 316327189671755572, + 1641324389046377921, + 7739989395386261137, + 1933903796324928314, ]), - y: FieldElement::from_mont([ - 14252083571674603243, - 12587053260418384210, - 4798858472748676776, + Felt::from_raw([ 81375596133053150, + 4798858472748676776, + 12587053260418384210, + 14252083571674603243, ]), - infinity: false, -}; -pub const PEDERSEN_P0: AffinePoint = AffinePoint { - x: FieldElement::from_mont([ - 3602345268353203007, - 13758484295849329960, - 518715844721862878, +); + +pub const PEDERSEN_P0: AffinePoint = AffinePoint::new_unchecked( + Felt::from_raw([ 241691544791834578, + 518715844721862878, + 13758484295849329960, + 3602345268353203007, ]), - y: FieldElement::from_mont([ - 13441546676070136227, - 13001553326386915570, - 433857700841878496, + Felt::from_raw([ 368891789801938570, + 433857700841878496, + 13001553326386915570, + 13441546676070136227, ]), - infinity: false, -}; -pub const PEDERSEN_P1: AffinePoint = AffinePoint { - x: FieldElement::from_mont([ - 16491878934996302286, - 12382025591154462459, - 10043949394709899044, +); + +pub const PEDERSEN_P1: AffinePoint = AffinePoint::new_unchecked( + Felt::from_raw([ 253000153565733272, + 10043949394709899044, + 12382025591154462459, + 16491878934996302286, ]), - y: FieldElement::from_mont([ - 13950428914333633429, - 2545498000137298346, - 5191292837124484988, + Felt::from_raw([ 285630633187035523, + 5191292837124484988, + 2545498000137298346, + 13950428914333633429, ]), - infinity: false, -}; -pub const PEDERSEN_P2: AffinePoint = AffinePoint { - x: FieldElement::from_mont([ - 1203723169299412240, - 18195981508842736832, - 12916675983929588442, +); + +pub const PEDERSEN_P2: AffinePoint = AffinePoint::new_unchecked( + Felt::from_raw([ 338510149841406402, + 12916675983929588442, + 18195981508842736832, + 1203723169299412240, ]), - y: FieldElement::from_mont([ - 12352616181161700245, - 11743524503750604092, - 11088962269971685343, + Felt::from_raw([ 161068411212710156, + 11088962269971685343, + 11743524503750604092, + 12352616181161700245, ]), - infinity: false, -}; -pub const PEDERSEN_P3: AffinePoint = AffinePoint { - x: FieldElement::from_mont([ - 1145636535101238356, - 10664803185694787051, - 299781701614706065, +); + +pub const PEDERSEN_P3: AffinePoint = AffinePoint::new_unchecked( + Felt::from_raw([ 425493972656615276, + 299781701614706065, + 10664803185694787051, + 1145636535101238356, ]), - y: FieldElement::from_mont([ - 8187986478389849302, - 4428713245976508844, - 6033691581221864148, + Felt::from_raw([ 345457391846365716, + 6033691581221864148, + 4428713245976508844, + 8187986478389849302, ]), - infinity: false, -}; +); diff --git a/starknet-curve/src/ec_point.rs b/starknet-curve/src/ec_point.rs deleted file mode 100644 index 6500480e..00000000 --- a/starknet-curve/src/ec_point.rs +++ /dev/null @@ -1,296 +0,0 @@ -use starknet_ff::FieldElement; - -use crate::curve_params::{ALPHA, BETA}; - -use core::ops; - -/// A point on an elliptic curve over [FieldElement]. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct AffinePoint { - pub x: FieldElement, - pub y: FieldElement, - pub infinity: bool, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct ProjectivePoint { - pub x: FieldElement, - pub y: FieldElement, - pub z: FieldElement, - pub infinity: bool, -} - -impl AffinePoint { - pub fn from_x(x: FieldElement) -> Option { - let y_squared = x * x * x + ALPHA * x + BETA; - y_squared.sqrt().map(|y| Self { - x, - y, - infinity: false, - }) - } - - fn identity() -> AffinePoint { - Self { - x: FieldElement::ZERO, - y: FieldElement::ZERO, - infinity: true, - } - } - - pub fn double_assign(&mut self) { - if self.infinity { - return; - } - - // l = (3x^2+a)/2y with a=1 from stark curve - let lambda = { - let dividend = FieldElement::THREE * (self.x * self.x) + FieldElement::ONE; - let divisor_inv = self.y.double().invert().unwrap(); - dividend * divisor_inv - }; - - let result_x = (lambda * lambda) - self.x - self.x; - self.y = lambda * (self.x - result_x) - self.y; - self.x = result_x; - } -} - -impl From<&ProjectivePoint> for AffinePoint { - fn from(p: &ProjectivePoint) -> Self { - let zinv = p.z.invert().unwrap(); - Self { - x: p.x * zinv, - y: p.y * zinv, - infinity: false, - } - } -} - -impl ops::Add<&AffinePoint> for &AffinePoint { - type Output = AffinePoint; - - fn add(self, rhs: &AffinePoint) -> Self::Output { - let mut copy = *self; - copy += rhs; - copy - } -} - -impl ops::AddAssign<&AffinePoint> for AffinePoint { - fn add_assign(&mut self, rhs: &AffinePoint) { - if rhs.infinity { - return; - } - if self.infinity { - *self = *rhs; - return; - } - if self.x == rhs.x { - if self.y == rhs.y { - self.double_assign(); - } else { - *self = AffinePoint::identity(); - } - return; - } - - let lambda = (rhs.y - self.y) * (rhs.x - self.x).invert().unwrap(); - - let result_x = lambda * lambda - self.x - rhs.x; - - self.y = lambda * (self.x - result_x) - self.y; - self.x = result_x; - } -} - -impl ops::Neg for &AffinePoint { - type Output = AffinePoint; - - fn neg(self) -> AffinePoint { - AffinePoint { - x: self.x, - y: -self.y, - infinity: self.infinity, - } - } -} - -impl ops::Sub<&AffinePoint> for &AffinePoint { - type Output = AffinePoint; - - fn sub(self, rhs: &AffinePoint) -> Self::Output { - let mut copy = *self; - copy -= rhs; - copy - } -} - -impl ops::SubAssign<&AffinePoint> for AffinePoint { - fn sub_assign(&mut self, rhs: &AffinePoint) { - *self += &-rhs; - } -} - -impl ops::Mul<&[bool]> for &AffinePoint { - type Output = AffinePoint; - - #[allow(clippy::suspicious_arithmetic_impl)] - fn mul(self, rhs: &[bool]) -> Self::Output { - let mut product = AffinePoint::identity(); - for b in rhs.iter().rev().skip_while(|b| !*b) { - product.double_assign(); - if *b { - product += self; - } - } - - product - } -} - -impl ProjectivePoint { - pub const fn from_affine_point(p: &AffinePoint) -> Self { - Self { - x: p.x, - y: p.y, - z: FieldElement::ONE, - infinity: p.infinity, - } - } - - fn identity() -> ProjectivePoint { - Self { - x: FieldElement::ZERO, - y: FieldElement::ZERO, - z: FieldElement::ONE, - infinity: true, - } - } - - pub fn double_assign(&mut self) { - if self.infinity { - return; - } - - // t=3x^2+az^2 with a=1 from stark curve - let t = FieldElement::THREE * self.x * self.x + self.z * self.z; - let u = self.y.double() * self.z; - let v = u.double() * self.x * self.y; - let w = t * t - v.double(); - - let uy = u * self.y; - - let x = u * w; - let y = t * (v - w) - (uy * uy).double(); - let z = u * u * u; - - self.x = x; - self.y = y; - self.z = z; - } -} - -impl From<&AffinePoint> for ProjectivePoint { - fn from(p: &AffinePoint) -> Self { - Self::from_affine_point(p) - } -} - -impl ops::AddAssign<&AffinePoint> for ProjectivePoint { - fn add_assign(&mut self, rhs: &AffinePoint) { - if rhs.infinity { - return; - } - if self.infinity { - *self = Self::from_affine_point(rhs); - return; - } - let u0 = self.x; - let u1 = rhs.x * self.z; - let t0 = self.y; - let t1 = rhs.y * self.z; - if u0 == u1 { - if t0 != t1 { - self.infinity = true; - } else { - self.double_assign(); - } - return; - } - - let t = t0 - t1; - let u = u0 - u1; - let u2 = u * u; - - let v = self.z; - let w = t * t * v - u2 * (u0 + u1); - let u3 = u * u2; - - let x = u * w; - let y = t * (u0 * u2 - w) - t0 * u3; - let z = u3 * v; - - self.x = x; - self.y = y; - self.z = z; - } -} - -impl ops::AddAssign<&ProjectivePoint> for ProjectivePoint { - fn add_assign(&mut self, rhs: &ProjectivePoint) { - if rhs.infinity { - return; - } - if self.infinity { - *self = *rhs; - return; - } - let u0 = self.x * rhs.z; - let u1 = rhs.x * self.z; - if u0 == u1 { - if self.y == rhs.y { - self.double_assign(); - } else { - *self = ProjectivePoint::identity(); - } - return; - } - - let t0 = self.y * rhs.z; - let t1 = rhs.y * self.z; - let t = t0 - t1; - - let u = u0 - u1; - let u2 = u * u; - - let v = self.z * rhs.z; - let w = t * t * v - u2 * (u0 + u1); - let u3 = u * u2; - - let x = u * w; - let y = t * (u0 * u2 - w) - t0 * u3; - let z = u3 * v; - - self.x = x; - self.y = y; - self.z = z; - } -} - -impl ops::Mul<&[bool]> for &ProjectivePoint { - type Output = ProjectivePoint; - - #[allow(clippy::suspicious_arithmetic_impl)] - fn mul(self, rhs: &[bool]) -> Self::Output { - let mut product = ProjectivePoint::identity(); - for b in rhs.iter().rev().skip_while(|b| !*b) { - product.double_assign(); - if *b { - product += self; - } - } - - product - } -} diff --git a/starknet-curve/src/lib.rs b/starknet-curve/src/lib.rs index d053fdef..a092b315 100644 --- a/starknet-curve/src/lib.rs +++ b/starknet-curve/src/lib.rs @@ -1,7 +1,4 @@ #![no_std] #![doc = include_str!("../README.md")] -mod ec_point; - pub mod curve_params; -pub use ec_point::{AffinePoint, ProjectivePoint}; diff --git a/starknet-ff/Cargo.toml b/starknet-ff/Cargo.toml deleted file mode 100644 index 29cc9d73..00000000 --- a/starknet-ff/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "starknet-ff" -version = "0.3.7" -authors = ["Jonathan LEI "] -license = "MIT OR Apache-2.0" -edition = "2021" -readme = "README.md" -repository = "https://github.com/xJonathanLEI/starknet-rs" -homepage = "https://starknet.rs/" -description = """ -Starknet field element type -""" -keywords = ["ethereum", "starknet", "web3", "no_std"] - -[package.metadata.docs.rs] -all-features = true - -[dependencies] -ark-ff = { version = "0.4.2", default-features = false } -crypto-bigint = { version = "0.5.1", default-features = false } -hex = { version = "0.4.3", default-features = false } -serde = { version = "1.0.160", optional = true, default-features = false } -bigdecimal = { version = "0.3.0", optional = true } -num-bigint = { version = "0.4.3", optional = true, default-features = false } - - -[features] -default = ["std", "serde"] -std = [] -alloc = ["serde?/alloc"] -serde = ["dep:serde", "alloc", "bigdecimal?/serde"] -bigdecimal = ["std", "dep:bigdecimal", "dep:num-bigint"] - -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2.9", features = ["js"] } - -[target.'cfg(target_arch = "wasm32")'.dev-dependencies] -wasm-bindgen-test = "0.3.34" diff --git a/starknet-ff/README.md b/starknet-ff/README.md deleted file mode 100644 index d29502f2..00000000 --- a/starknet-ff/README.md +++ /dev/null @@ -1 +0,0 @@ -# Starknet field element type diff --git a/starknet-ff/src/fr.rs b/starknet-ff/src/fr.rs deleted file mode 100644 index 854c06c2..00000000 --- a/starknet-ff/src/fr.rs +++ /dev/null @@ -1,8 +0,0 @@ -use ark_ff::fields::{Fp256, MontBackend, MontConfig}; - -pub type Fr = Fp256>; - -#[derive(MontConfig)] -#[modulus = "3618502788666131213697322783095070105623107215331596699973092056135872020481"] -#[generator = "3"] -pub struct FrConfig; diff --git a/starknet-ff/src/lib.rs b/starknet-ff/src/lib.rs deleted file mode 100644 index 706bbcf2..00000000 --- a/starknet-ff/src/lib.rs +++ /dev/null @@ -1,1110 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] -#![allow(clippy::comparison_chain)] - -#[cfg(all(not(feature = "std"), any(test, feature = "alloc")))] -#[cfg_attr(test, macro_use)] -extern crate alloc; - -use core::{ - fmt, ops, - str::{self, FromStr}, -}; - -use crate::fr::Fr; - -use ark_ff::{ - fields::{Field, Fp256, PrimeField}, - BigInteger, BigInteger256, -}; -use crypto_bigint::{CheckedAdd, CheckedMul, NonZero, Zero, U256}; - -mod fr; - -const U256_BYTE_COUNT: usize = 32; - -#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)] -pub struct FieldElement { - inner: Fr, -} - -mod from_str_error { - - #[derive(Debug)] - pub enum FromStrError { - InvalidCharacter, - OutOfRange, - } - - #[cfg(feature = "std")] - impl std::error::Error for FromStrError {} - - impl core::fmt::Display for FromStrError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::InvalidCharacter => write!(f, "invalid character"), - Self::OutOfRange => write!(f, "number out of range"), - } - } - } -} -pub use from_str_error::FromStrError; - -mod from_bytes_slice_error { - - #[derive(Debug)] - pub enum FromByteSliceError { - InvalidLength, - OutOfRange, - } - - #[cfg(feature = "std")] - impl std::error::Error for FromByteSliceError {} - - impl core::fmt::Display for FromByteSliceError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::InvalidLength => write!(f, "invalid length"), - Self::OutOfRange => write!(f, "number out of range"), - } - } - } -} -pub use from_bytes_slice_error::FromByteSliceError; - -mod from_byte_array_error { - #[derive(Debug)] - pub struct FromByteArrayError; - - #[cfg(feature = "std")] - impl std::error::Error for FromByteArrayError {} - - impl core::fmt::Display for FromByteArrayError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "number out of range") - } - } -} -pub use from_byte_array_error::FromByteArrayError; - -mod value_out_of_range_error { - #[derive(Debug)] - pub struct ValueOutOfRangeError; - - #[cfg(feature = "std")] - impl std::error::Error for ValueOutOfRangeError {} - - impl core::fmt::Display for ValueOutOfRangeError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "field element value out of range") - } - } -} -pub use value_out_of_range_error::ValueOutOfRangeError; - -struct InnerDebug<'a>(pub &'a FieldElement); - -impl FieldElement { - /// [FieldElement] constant that's equal to 0 - pub const ZERO: FieldElement = FieldElement::from_mont([0, 0, 0, 0]); - - /// [FieldElement] constant that's equal to 1 - pub const ONE: FieldElement = FieldElement::from_mont([ - 18446744073709551585, - 18446744073709551615, - 18446744073709551615, - 576460752303422960, - ]); - - /// [FieldElement] constant that's equal to 2 - pub const TWO: FieldElement = FieldElement::from_mont([ - 18446744073709551553, - 18446744073709551615, - 18446744073709551615, - 576460752303422416, - ]); - - /// [FieldElement] constant that's equal to 3 - pub const THREE: FieldElement = FieldElement::from_mont([ - 18446744073709551521, - 18446744073709551615, - 18446744073709551615, - 576460752303421872, - ]); - - /// Maximum value of [FieldElement]. Equals to 2^251 + 17 * 2^192. - pub const MAX: FieldElement = FieldElement::from_mont([32, 0, 0, 544]); - - /// Create a new [FieldElement] from its Montgomery representation - pub const fn from_mont(data: [u64; 4]) -> Self { - Self { - inner: Fp256::new_unchecked(BigInteger256::new(data)), - } - } - - pub fn from_dec_str(value: &str) -> Result { - // Ported from: - // https://github.com/paritytech/parity-common/blob/b37d0b312d39fa47c61c4430b30ca87d90e45a08/uint/src/uint.rs#L599 - - let mut res = U256::ZERO; - for b in value.bytes().map(|b| b.wrapping_sub(b'0')) { - if b > 9 { - return Err(FromStrError::InvalidCharacter); - } - let r = { - let product = res.checked_mul(&U256::from_u8(10)); - if product.is_some().into() { - product.unwrap() - } else { - return Err(FromStrError::OutOfRange); - } - }; - let r = { - let sum = r.checked_add(&U256::from_u8(b)); - if sum.is_some().into() { - sum.unwrap() - } else { - return Err(FromStrError::OutOfRange); - } - }; - res = r; - } - - Fr::from_bigint(u256_to_biginteger256(&res)) - .map(|inner| Self { inner }) - .ok_or(FromStrError::OutOfRange) - } - - pub fn from_hex_be(value: &str) -> Result { - let value = value.trim_start_matches("0x"); - - let hex_chars_len = value.len(); - let expected_hex_length = U256_BYTE_COUNT * 2; - - let parsed_bytes: [u8; U256_BYTE_COUNT] = if hex_chars_len == expected_hex_length { - let mut buffer = [0u8; U256_BYTE_COUNT]; - hex::decode_to_slice(value, &mut buffer).map_err(|_| FromStrError::InvalidCharacter)?; - buffer - } else if hex_chars_len < expected_hex_length { - let mut padded_hex = str::repeat("0", expected_hex_length - hex_chars_len); - padded_hex.push_str(value); - - let mut buffer = [0u8; U256_BYTE_COUNT]; - hex::decode_to_slice(&padded_hex, &mut buffer) - .map_err(|_| FromStrError::InvalidCharacter)?; - buffer - } else { - return Err(FromStrError::OutOfRange); - }; - - match Self::from_bytes_be(&parsed_bytes) { - Ok(value) => Ok(value), - Err(_) => Err(FromStrError::OutOfRange), - } - } - - /// Attempts to convert a big-endian byte representation of a field element into an element of - /// this prime field. Returns error if the input is not canonical (is not smaller than the - /// field's modulus). - /// - /// ### Arguments - /// - /// * `bytes`: The byte array in **big endian** format - pub fn from_bytes_be(bytes: &[u8; 32]) -> Result { - Self::from_byte_slice(bytes).ok_or(FromByteArrayError) - } - - /// Same as `from_bytes_be` except this function takes a slice. - pub fn from_byte_slice_be(bytes: &[u8]) -> Result { - if bytes.len() > U256_BYTE_COUNT { - Err(FromByteSliceError::InvalidLength) - } else { - let mut buffer = [0u8; U256_BYTE_COUNT]; - buffer[(U256_BYTE_COUNT - bytes.len())..].copy_from_slice(bytes); - Self::from_byte_slice(&buffer).ok_or(FromByteSliceError::OutOfRange) - } - } - - /// Interprets the field element as a decimal number of a certain decimal places. - #[cfg(feature = "bigdecimal")] - pub fn to_big_decimal>(&self, decimals: D) -> bigdecimal::BigDecimal { - use num_bigint::{BigInt, Sign}; - - bigdecimal::BigDecimal::new( - BigInt::from_bytes_be(Sign::Plus, &self.to_bytes_be()), - decimals.into(), - ) - } - - /// Transforms [FieldElement] into little endian bit representation. - pub fn to_bits_le(self) -> [bool; 256] { - let mut bits = [false; 256]; - for (ind_element, element) in self.inner.into_bigint().0.iter().enumerate() { - for ind_bit in 0..64 { - bits[ind_element * 64 + ind_bit] = (element >> ind_bit) & 1 == 1; - } - } - - bits - } - - /// Convert the field element into a big-endian byte representation - pub fn to_bytes_be(&self) -> [u8; 32] { - let mut buffer = [0u8; 32]; - buffer.copy_from_slice(&self.inner.into_bigint().to_bytes_be()); - - buffer - } - - /// Transforms [FieldElement] into its Montgomery representation - pub const fn into_mont(self) -> [u64; 4] { - self.inner.0 .0 - } - - pub fn invert(&self) -> Option { - self.inner.inverse().map(|inner| Self { inner }) - } - - pub fn sqrt(&self) -> Option { - self.inner.sqrt().map(|inner| Self { inner }) - } - - pub fn double(&self) -> FieldElement { - *self + *self - } - - /// Performs a floor division. It's not implemented as the `Div` trait on purpose to - /// distinguish from the "felt division". - pub fn floor_div(&self, rhs: FieldElement) -> FieldElement { - let lhs: U256 = self.into(); - let rhs: U256 = (&rhs).into(); - let is_rhs_zero: bool = rhs.is_zero().into(); - - if !is_rhs_zero { - let rhs = NonZero::from_uint(rhs); - - let div_result = lhs.div_rem(&rhs); - let (quotient, _) = div_result; - - // It's safe to unwrap here since `rem` is never out of range - FieldElement { - inner: Fr::from_bigint(u256_to_biginteger256("ient)).unwrap(), - } - } else { - // TODO: add `checked_floor_div` for panic-less use - panic!("division by zero"); - } - } - - /// For internal use only. The input must be of length [U256_BYTE_COUNT]. - fn from_byte_slice(bytes: &[u8]) -> Option { - let mut bits = [false; U256_BYTE_COUNT * 8]; - for (ind_byte, byte) in bytes.iter().enumerate() { - for ind_bit in 0..8 { - bits[ind_byte * 8 + ind_bit] = (byte >> (7 - ind_bit)) & 1 == 1; - } - } - - // No need to check range as `from_bigint` already does that - let big_int = BigInteger256::from_bits_be(&bits); - Fr::from_bigint(big_int).map(|inner| Self { inner }) - } -} - -impl Default for FieldElement { - fn default() -> Self { - Self::ZERO - } -} - -impl AsRef for FieldElement { - fn as_ref(&self) -> &FieldElement { - self - } -} - -impl ops::Add for FieldElement { - type Output = FieldElement; - - fn add(self, rhs: FieldElement) -> Self::Output { - FieldElement { - inner: self.inner + rhs.inner, - } - } -} - -impl ops::AddAssign for FieldElement { - fn add_assign(&mut self, rhs: FieldElement) { - self.inner = self.inner + rhs.inner; - } -} - -impl ops::Sub for FieldElement { - type Output = FieldElement; - - fn sub(self, rhs: FieldElement) -> Self::Output { - FieldElement { - inner: self.inner - rhs.inner, - } - } -} - -impl ops::SubAssign for FieldElement { - fn sub_assign(&mut self, rhs: FieldElement) { - self.inner = self.inner - rhs.inner; - } -} - -impl ops::Mul for FieldElement { - type Output = FieldElement; - - fn mul(self, rhs: FieldElement) -> Self::Output { - FieldElement { - inner: self.inner * rhs.inner, - } - } -} - -impl ops::MulAssign for FieldElement { - fn mul_assign(&mut self, rhs: FieldElement) { - self.inner = self.inner * rhs.inner; - } -} - -impl ops::Neg for FieldElement { - type Output = FieldElement; - - fn neg(self) -> Self::Output { - FieldElement { inner: -self.inner } - } -} - -impl ops::Rem for FieldElement { - type Output = FieldElement; - - fn rem(self, rhs: FieldElement) -> Self::Output { - if self.inner < rhs.inner { - return self; - } - - let lhs: U256 = (&self).into(); - let rhs: U256 = (&rhs).into(); - let is_rhs_zero: bool = rhs.is_zero().into(); - - if !is_rhs_zero { - let rhs = NonZero::from_uint(rhs); - - let (_, rem) = lhs.div_rem(&rhs); - - // It's safe to unwrap here since `rem` is never out of range - FieldElement { - inner: Fr::from_bigint(u256_to_biginteger256(&rem)).unwrap(), - } - } else { - // TODO: add `checked_rem` for panic-less use - panic!("division by zero"); - } - } -} - -impl ops::BitAnd for FieldElement { - type Output = FieldElement; - - fn bitand(self, rhs: FieldElement) -> Self::Output { - let lhs: U256 = (&self).into(); - let rhs: U256 = (&rhs).into(); - - // It's safe to unwrap here since the result is never out of range - FieldElement { - inner: Fr::from_bigint(u256_to_biginteger256(&(lhs & rhs))).unwrap(), - } - } -} - -impl ops::BitOr for FieldElement { - type Output = FieldElement; - - fn bitor(self, rhs: FieldElement) -> Self::Output { - let lhs: U256 = (&self).into(); - let rhs: U256 = (&rhs).into(); - - // It's safe to unwrap here since the result is never out of range - FieldElement { - inner: Fr::from_bigint(u256_to_biginteger256(&(lhs | rhs))).unwrap(), - } - } -} - -impl core::iter::Sum for FieldElement { - fn sum>(iter: I) -> Self { - let mut sum = Self::ZERO; - iter.for_each(|item| { - sum += item; - }); - sum - } -} - -impl<'a> core::iter::Sum<&'a FieldElement> for FieldElement { - fn sum>(iter: I) -> Self { - iter.copied().sum() - } -} - -impl fmt::Debug for FieldElement { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FieldElement") - .field("inner", &InnerDebug(self)) - .finish() - } -} - -impl fmt::Display for FieldElement { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Ported from: - // https://github.com/paritytech/parity-common/blob/b37d0b312d39fa47c61c4430b30ca87d90e45a08/uint/src/uint.rs#L1650 - - let repr: U256 = self.into(); - - if repr.is_zero().into() { - return write!(f, "0"); - } - - let mut buf = [0u8; 4 * 20]; - let mut i = buf.len() - 1; - let mut current = repr; - let ten = U256::from_u8(10u8); - - loop { - let digit = if current < ten { - current.to_words()[0] as u8 - } else { - (current.checked_rem(&ten)).unwrap().to_words()[0] as u8 - }; - buf[i] = digit + b'0'; - current = current.checked_div(&ten).unwrap(); - if current.is_zero().into() { - break; - } - i -= 1; - } - - // sequence of `'0'..'9'` chars is guaranteed to be a valid UTF8 string - let s = unsafe { str::from_utf8_unchecked(&buf[i..]) }; - f.pad_integral(true, "", s) - } -} - -impl fmt::LowerHex for FieldElement { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let repr: U256 = self.into(); - - let width = if f.sign_aware_zero_pad() { - f.width().unwrap().min(64) - } else { - 1 - }; - if f.alternate() { - write!(f, "0x")?; - } - let mut latch = false; - let mut ind_nibble = 0; - for ch in u256_to_u64_array(&repr).iter().rev() { - for x in 0..16 { - let nibble = (ch & (15u64 << ((15 - x) * 4) as u64)) >> (((15 - x) * 4) as u64); - if !latch { - latch = nibble != 0 || (64 - ind_nibble <= width); - } - if latch { - write!(f, "{nibble:x}")?; - } - ind_nibble += 1; - } - } - Ok(()) - } -} - -impl fmt::UpperHex for FieldElement { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let repr: U256 = self.into(); - - let width = if f.sign_aware_zero_pad() { - f.width().unwrap().min(64) - } else { - 1 - }; - if f.alternate() { - write!(f, "0x")?; - } - let mut latch = false; - let mut ind_nibble = 0; - for ch in u256_to_u64_array(&repr).iter().rev() { - for x in 0..16 { - let nibble = (ch & (15u64 << ((15 - x) * 4) as u64)) >> (((15 - x) * 4) as u64); - if !latch { - latch = nibble != 0 || (64 - ind_nibble <= width); - } - if latch { - write!(f, "{nibble:X}")?; - } - ind_nibble += 1; - } - } - Ok(()) - } -} - -#[cfg(feature = "serde")] -mod serde_field_element { - #[cfg(feature = "std")] - use core::fmt::{Formatter, Result as FmtResult}; - - use super::*; - #[cfg(not(feature = "std"))] - use alloc::{ - fmt::{Formatter, Result as FmtResult}, - string::ToString, - }; - use serde::{de::Visitor, Deserialize, Serialize}; - - struct FieldElementVisitor; - - impl Serialize for FieldElement { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&ToString::to_string(&self)) - } - } - - impl<'de> Deserialize<'de> for FieldElement { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_str(FieldElementVisitor) - } - } - - impl<'de> Visitor<'de> for FieldElementVisitor { - type Value = FieldElement; - - fn expecting(&self, formatter: &mut Formatter) -> FmtResult { - write!(formatter, "string") - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - FieldElement::from_str(v).map_err(serde::de::Error::custom) - } - } -} - -impl From for FieldElement { - fn from(value: u8) -> Self { - Self { - inner: Fr::from_bigint(BigInteger256::new([value as u64, 0, 0, 0])).unwrap(), - } - } -} - -impl From for FieldElement { - fn from(value: u16) -> Self { - Self { - inner: Fr::from_bigint(BigInteger256::new([value as u64, 0, 0, 0])).unwrap(), - } - } -} - -impl From for FieldElement { - fn from(value: u32) -> Self { - Self { - inner: Fr::from_bigint(BigInteger256::new([value as u64, 0, 0, 0])).unwrap(), - } - } -} - -impl From for FieldElement { - fn from(value: u64) -> Self { - Self { - inner: Fr::from_bigint(BigInteger256::new([value, 0, 0, 0])).unwrap(), - } - } -} - -impl From for FieldElement { - fn from(value: u128) -> Self { - let low = value % (u64::MAX as u128 + 1); - let high = value / (u64::MAX as u128 + 1); - - Self { - inner: Fr::from_bigint(BigInteger256::new([low as u64, high as u64, 0, 0])).unwrap(), - } - } -} - -impl From for FieldElement { - fn from(value: usize) -> Self { - Self { - inner: Fr::from_bigint(BigInteger256::new([value as u64, 0, 0, 0])).unwrap(), - } - } -} - -impl FromStr for FieldElement { - type Err = FromStrError; - - fn from_str(s: &str) -> Result { - if s.starts_with("0x") { - FieldElement::from_hex_be(s) - } else { - FieldElement::from_dec_str(s) - } - } -} - -impl TryFrom for u8 { - type Error = ValueOutOfRangeError; - - fn try_from(value: FieldElement) -> Result { - let repr = value.inner.into_bigint().0; - if repr[0] > u8::MAX as u64 || repr[1] > 0 || repr[2] > 0 || repr[3] > 0 { - Err(ValueOutOfRangeError) - } else { - Ok(repr[0] as u8) - } - } -} - -impl TryFrom for u16 { - type Error = ValueOutOfRangeError; - - fn try_from(value: FieldElement) -> Result { - let repr = value.inner.into_bigint().0; - if repr[0] > u16::MAX as u64 || repr[1] > 0 || repr[2] > 0 || repr[3] > 0 { - Err(ValueOutOfRangeError) - } else { - Ok(repr[0] as u16) - } - } -} - -impl TryFrom for u32 { - type Error = ValueOutOfRangeError; - - fn try_from(value: FieldElement) -> Result { - let repr = value.inner.into_bigint().0; - if repr[0] > u32::MAX as u64 || repr[1] > 0 || repr[2] > 0 || repr[3] > 0 { - Err(ValueOutOfRangeError) - } else { - Ok(repr[0] as u32) - } - } -} - -impl TryFrom for u64 { - type Error = ValueOutOfRangeError; - - fn try_from(value: FieldElement) -> Result { - let repr = value.inner.into_bigint().0; - if repr[1] > 0 || repr[2] > 0 || repr[3] > 0 { - Err(ValueOutOfRangeError) - } else { - Ok(repr[0]) - } - } -} - -impl TryFrom for u128 { - type Error = ValueOutOfRangeError; - - fn try_from(value: FieldElement) -> Result { - let repr = value.inner.into_bigint().0; - if repr[2] > 0 || repr[3] > 0 { - Err(ValueOutOfRangeError) - } else { - Ok((repr[0] as u128) + (repr[1] as u128) * (u64::MAX as u128 + 1)) - } - } -} - -impl From<&FieldElement> for U256 { - #[cfg(target_pointer_width = "64")] - fn from(value: &FieldElement) -> Self { - U256::from_words(value.inner.into_bigint().0) - } - - #[cfg(target_pointer_width = "32")] - fn from(value: &FieldElement) -> Self { - U256::from_words(unsafe { - core::mem::transmute::<[u64; 4], [u32; 8]>(value.inner.into_bigint().0) - }) - } -} - -impl<'a> fmt::Debug for InnerDebug<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:#064x}", self.0) - } -} - -#[inline] -fn u256_to_biginteger256(num: &U256) -> BigInteger256 { - BigInteger256::new(u256_to_u64_array(num)) -} - -#[cfg(target_pointer_width = "64")] -#[inline] -fn u256_to_u64_array(num: &U256) -> [u64; 4] { - num.to_words() -} - -#[cfg(target_pointer_width = "32")] -#[inline] -fn u256_to_u64_array(num: &U256) -> [u64; 4] { - unsafe { core::mem::transmute::<[u32; 8], [u64; 4]>(num.to_words()) } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_default_value() { - assert_eq!(FieldElement::default(), FieldElement::ZERO) - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_dec_fmt() { - let nums = [ - "0", - "1", - "10", - "11", - "3618502788666131213697322783095070105623107215331596699973092056135872020480", - ]; - - for num in nums.iter() { - assert_eq!( - &format!("{}", FieldElement::from_dec_str(num).unwrap()), - num - ); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_zero_padded_hex_fmt() { - let fe = FieldElement::from_hex_be("0x1234abcd").unwrap(); - - assert_eq!(format!("{fe:011x}"), "0001234abcd"); - assert_eq!(format!("{fe:011X}"), "0001234ABCD"); - assert_eq!(format!("{fe:08x}"), "1234abcd"); - assert_eq!(format!("{fe:06x}"), "1234abcd"); - assert_eq!(format!("{fe:#x}"), "0x1234abcd"); - assert_eq!( - format!("{fe:#064x}"), - "0x000000000000000000000000000000000000000000000000000000001234abcd" - ); - - // Ignore if requesting more than 64 nibbles (or should we not?) - assert_eq!( - format!("{fe:#0100x}"), - "0x000000000000000000000000000000000000000000000000000000001234abcd" - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_addition() { - let additions = [ - ["1", "1", "2"], - [ - "3618502788666131213697322783095070105623107215331596699973092056135872020480", - "1", - "0", - ], - ]; - - for item in additions.iter() { - let mut lhs = FieldElement::from_dec_str(item[0]).unwrap(); - let rhs = FieldElement::from_dec_str(item[1]).unwrap(); - let result = FieldElement::from_dec_str(item[2]).unwrap(); - assert_eq!(lhs + rhs, result); - - lhs += rhs; - assert_eq!(lhs, result); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_subtraction() { - let subtractions = [ - ["10", "7", "3"], - [ - "0", - "3618502788666131213697322783095070105623107215331596699973092056135872020480", - "1", - ], - ]; - - for item in subtractions.iter() { - let mut lhs = FieldElement::from_dec_str(item[0]).unwrap(); - let rhs = FieldElement::from_dec_str(item[1]).unwrap(); - let result = FieldElement::from_dec_str(item[2]).unwrap(); - assert_eq!(lhs - rhs, result); - - lhs -= rhs; - assert_eq!(lhs, result); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_multiplication() { - let multiplications = [ - ["2", "3", "6"], - [ - "3618502788666131213697322783095070105623107215331596699973092056135872020480", - "3618502788666131213697322783095070105623107215331596699973092056135872020480", - "1", - ], - [ - "3141592653589793238462643383279502884197169399375105820974944592307", - "8164062862089986280348253421170679821480865132823066470938446095505", - "514834056922159274131066670130609582664841480950767778400381816737396274242", - ], - ]; - - for item in multiplications.iter() { - let mut lhs = FieldElement::from_dec_str(item[0]).unwrap(); - let rhs = FieldElement::from_dec_str(item[1]).unwrap(); - let result = FieldElement::from_dec_str(item[2]).unwrap(); - assert_eq!(lhs * rhs, result); - - lhs *= rhs; - assert_eq!(lhs, result); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_remainder() { - let remainders = [["123456", "100", "56"], ["7", "3", "1"], ["3", "6", "3"]]; - - for item in remainders.iter() { - assert_eq!( - FieldElement::from_dec_str(item[0]).unwrap() - % FieldElement::from_dec_str(item[1]).unwrap(), - FieldElement::from_dec_str(item[2]).unwrap() - ); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_bitwise_and() { - let operands = [[123456_u64, 567890], [613221132151, 4523451]]; - - for item in operands.iter() { - let lhs: FieldElement = item[0].into(); - let rhs: FieldElement = item[1].into(); - assert_eq!(lhs & rhs, (item[0] & item[1]).into()); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_bitwise_or() { - let operands = [[123456_u64, 567890], [613221132151, 4523451]]; - - for item in operands.iter() { - let lhs: FieldElement = item[0].into(); - let rhs: FieldElement = item[1].into(); - assert_eq!(lhs | rhs, (item[0] | item[1]).into()); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_iter_sum() { - let elements = [FieldElement::ONE, FieldElement::TWO, FieldElement::THREE]; - - assert_eq!( - elements.iter().sum::(), - FieldElement::from_dec_str("6").unwrap() - ); - assert_eq!( - elements.into_iter().sum::(), - FieldElement::from_dec_str("6").unwrap() - ); - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_floor_division() { - let quotients = [["123456", "100", "1234"], ["7", "3", "2"], ["3", "6", "0"]]; - - for item in quotients.iter() { - assert_eq!( - FieldElement::from_dec_str(item[0]) - .unwrap() - .floor_div(FieldElement::from_dec_str(item[1]).unwrap()), - FieldElement::from_dec_str(item[2]).unwrap() - ); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_to_primitives() { - let fe_256: FieldElement = 256u16.into(); - - if u8::try_from(fe_256).is_ok() { - panic!("invalid conversion"); - } - - assert_eq!(u16::try_from(fe_256).unwrap(), 256u16); - assert_eq!(u32::try_from(fe_256).unwrap(), 256u32); - assert_eq!(u64::try_from(fe_256).unwrap(), 256u64); - } - - #[test] - #[cfg(feature = "bigdecimal")] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_to_big_decimal() { - use bigdecimal::{BigDecimal, Num}; - - let nums = [ - ( - "134500", - 5, - BigDecimal::from_str_radix("1.345", 10).unwrap(), - ), - ( - "134500", - 0, - BigDecimal::from_str_radix("134500", 10).unwrap(), - ), - ( - "134500", - 10, - BigDecimal::from_str_radix("0.00001345", 10).unwrap(), - ), - ]; - - for num in nums.into_iter() { - assert_eq!( - FieldElement::from_dec_str(num.0) - .unwrap() - .to_big_decimal(num.1), - num.2 - ); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_from_str() { - let nums = [ - ("134500", "0x20d64"), - ("9999999999999999", "0x2386f26fc0ffff"), - ]; - - for num in nums.into_iter() { - assert_eq!( - num.0.parse::().unwrap(), - num.1.parse::().unwrap(), - ); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_from_byte_slice_be() { - let nums = [("25800", [100u8, 200u8])]; - - for num in nums.into_iter() { - assert_eq!( - num.0.parse::().unwrap(), - FieldElement::from_byte_slice_be(&num.1).unwrap() - ); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_u8_conversion() { - let nums = [u8::MAX, u8::MAX / 3 * 2, u8::MAX / 3]; - - for num in nums.into_iter() { - let felt: FieldElement = num.into(); - assert_eq!(format!("{}", felt), format!("{}", num)); - - let back_to_num: u8 = felt.try_into().unwrap(); - assert_eq!(num, back_to_num); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_u16_conversion() { - let nums = [u16::MAX, u16::MAX / 3 * 2, u16::MAX / 3]; - - for num in nums.into_iter() { - let felt: FieldElement = num.into(); - assert_eq!(format!("{}", felt), format!("{}", num)); - - let back_to_num: u16 = felt.try_into().unwrap(); - assert_eq!(num, back_to_num); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_u32_conversion() { - let nums = [u32::MAX, u32::MAX / 3 * 2, u32::MAX / 3]; - - for num in nums.into_iter() { - let felt: FieldElement = num.into(); - assert_eq!(format!("{}", felt), format!("{}", num)); - - let back_to_num: u32 = felt.try_into().unwrap(); - assert_eq!(num, back_to_num); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_u64_conversion() { - let nums = [u64::MAX, u64::MAX / 3 * 2, u64::MAX / 3]; - - for num in nums.into_iter() { - let felt: FieldElement = num.into(); - assert_eq!(format!("{}", felt), format!("{}", num)); - - let back_to_num: u64 = felt.try_into().unwrap(); - assert_eq!(num, back_to_num); - } - } - - #[test] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] - fn test_u128_conversion() { - let nums = [u128::MAX, u128::MAX / 3 * 2, u128::MAX / 3]; - - for num in nums.into_iter() { - let felt: FieldElement = num.into(); - assert_eq!(format!("{}", felt), format!("{}", num)); - - let back_to_num: u128 = felt.try_into().unwrap(); - assert_eq!(num, back_to_num); - } - } -} diff --git a/starknet-macros/Cargo.toml b/starknet-macros/Cargo.toml index 774f70ac..e402e0fb 100644 --- a/starknet-macros/Cargo.toml +++ b/starknet-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-macros" -version = "0.1.7" +version = "0.2.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -16,9 +16,12 @@ keywords = ["ethereum", "starknet", "web3"] proc-macro = true [dependencies] -starknet-core = { version = "0.10.0", path = "../starknet-core" } +starknet-core = { version = "0.11.1", path = "../starknet-core" } syn = "2.0.15" [features] default = [] use_imported_type = [] + +[lints] +workspace = true diff --git a/starknet-macros/src/lib.rs b/starknet-macros/src/lib.rs index 1d887834..79d1aade 100644 --- a/starknet-macros/src/lib.rs +++ b/starknet-macros/src/lib.rs @@ -1,6 +1,6 @@ use proc_macro::TokenStream; use starknet_core::{ - types::FieldElement, + types::Felt, utils::{cairo_short_string_to_felt, get_selector_from_name}, }; use syn::{parse_macro_input, LitStr}; @@ -12,10 +12,10 @@ pub fn selector(input: TokenStream) -> TokenStream { let str_value = input.value(); let selector_value = get_selector_from_name(&str_value).expect("invalid selector name"); - let selector_raw = selector_value.into_mont(); + let selector_raw = selector_value.to_raw(); format!( - "{}::from_mont([{}, {}, {}, {}])", + "{}::from_raw([{}, {}, {}, {}])", field_element_path(), selector_raw[0], selector_raw[1], @@ -33,10 +33,10 @@ pub fn short_string(input: TokenStream) -> TokenStream { let str_value = input.value(); let felt_value = cairo_short_string_to_felt(&str_value).expect("invalid Cairo short string"); - let felt_raw = felt_value.into_mont(); + let felt_raw = felt_value.to_raw(); format!( - "{}::from_mont([{}, {}, {}, {}])", + "{}::from_raw([{}, {}, {}, {}])", field_element_path(), felt_raw[0], felt_raw[1], @@ -54,15 +54,15 @@ pub fn felt(input: TokenStream) -> TokenStream { let str_value = input.value(); let felt_value = if str_value.starts_with("0x") { - FieldElement::from_hex_be(&str_value).expect("invalid FieldElement value") + Felt::from_hex(&str_value).expect("invalid Felt value") } else { - FieldElement::from_dec_str(&str_value).expect("invalid FieldElement value") + Felt::from_dec_str(&str_value).expect("invalid Felt value") }; - let felt_raw = felt_value.into_mont(); + let felt_raw = felt_value.to_raw(); format!( - "{}::from_mont([{}, {}, {}, {}])", + "{}::from_raw([{}, {}, {}, {}])", field_element_path(), felt_raw[0], felt_raw[1], @@ -79,11 +79,11 @@ pub fn felt_dec(input: TokenStream) -> TokenStream { let str_value = input.value(); - let felt_value = FieldElement::from_dec_str(&str_value).expect("invalid FieldElement value"); - let felt_raw = felt_value.into_mont(); + let felt_value = Felt::from_dec_str(&str_value).expect("invalid Felt value"); + let felt_raw = felt_value.to_raw(); format!( - "{}::from_mont([{}, {}, {}, {}])", + "{}::from_raw([{}, {}, {}, {}])", field_element_path(), felt_raw[0], felt_raw[1], @@ -100,11 +100,11 @@ pub fn felt_hex(input: TokenStream) -> TokenStream { let str_value = input.value(); - let felt_value = FieldElement::from_hex_be(&str_value).expect("invalid FieldElement value"); - let felt_raw = felt_value.into_mont(); + let felt_value = Felt::from_hex(&str_value).expect("invalid Felt value"); + let felt_raw = felt_value.to_raw(); format!( - "{}::from_mont([{}, {}, {}, {}])", + "{}::from_raw([{}, {}, {}, {}])", field_element_path(), felt_raw[0], felt_raw[1], @@ -117,10 +117,10 @@ pub fn felt_hex(input: TokenStream) -> TokenStream { #[cfg(feature = "use_imported_type")] fn field_element_path() -> &'static str { - "FieldElement" + "Felt" } #[cfg(not(feature = "use_imported_type"))] -fn field_element_path() -> &'static str { - "::starknet::core::types::FieldElement" +const fn field_element_path() -> &'static str { + "::starknet::core::types::Felt" } diff --git a/starknet-providers/Cargo.toml b/starknet-providers/Cargo.toml index 08da4cd8..15055413 100644 --- a/starknet-providers/Cargo.toml +++ b/starknet-providers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-providers" -version = "0.10.0" +version = "0.11.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -14,7 +14,7 @@ keywords = ["ethereum", "starknet", "web3"] exclude = ["test-data/**"] [dependencies] -starknet-core = { version = "0.10.0", path = "../starknet-core" } +starknet-core = { version = "0.11.1", path = "../starknet-core" } async-trait = "0.1.68" auto_impl = "1.0.1" ethereum-types = "0.14.1" @@ -25,7 +25,10 @@ reqwest = { version = "0.11.16", default-features = false, features = ["rustls-t thiserror = "1.0.40" serde = "1.0.160" serde_json = "1.0.96" -serde_with = "2.3.2" +serde_with = "3.9.0" + +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { version = "0.2.9", features = ["js"] } [dev-dependencies] starknet-providers = { path = ".", features = ["no_unknown_fields"] } @@ -36,3 +39,6 @@ default = [] no_unknown_fields = [ "starknet-core/no_unknown_fields" ] + +[lints] +workspace = true diff --git a/starknet-providers/src/any.rs b/starknet-providers/src/any.rs index 695985d3..0d04255c 100644 --- a/starknet-providers/src/any.rs +++ b/starknet-providers/src/any.rs @@ -4,7 +4,7 @@ use starknet_core::types::{ BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction, BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, BroadcastedTransaction, ContractClass, DeclareTransactionResult, DeployAccountTransactionResult, EventFilter, - EventsPage, FeeEstimate, FieldElement, FunctionCall, InvokeTransactionResult, + EventsPage, FeeEstimate, Felt, FunctionCall, InvokeTransactionResult, MaybePendingBlockWithReceipts, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate, MsgFromL1, SimulatedTransaction, SimulationFlag, SimulationFlagForEstimateFee, SyncStatusType, Transaction, TransactionReceiptWithBlockInfo, @@ -21,7 +21,7 @@ use crate::{ /// the [Provider] trait itself cannot be Box-ed due to the use of associated type. /// /// A recommended pattern is to make your business logic code (e.g. functions) generic over the -/// [Provider] trait, while using this [AnyProvider] type for bootstrapping your application. +/// [Provider] trait, while using this [`AnyProvider`] type for bootstrapping your application. /// /// NOTE: This type was introduced when [Provider] was not Box-able. It should be reviewed whether /// it's still needed anymore. @@ -125,10 +125,10 @@ impl Provider for AnyProvider { contract_address: A, key: K, block_id: B, - ) -> Result + ) -> Result where - A: AsRef + Send + Sync, - K: AsRef + Send + Sync, + A: AsRef + Send + Sync, + K: AsRef + Send + Sync, B: AsRef + Send + Sync, { match self { @@ -158,7 +158,7 @@ impl Provider for AnyProvider { transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { match self { Self::JsonRpcHttp(inner) => { @@ -183,7 +183,7 @@ impl Provider for AnyProvider { transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { match self { Self::JsonRpcHttp(inner) => { @@ -232,7 +232,7 @@ impl Provider for AnyProvider { transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { match self { Self::JsonRpcHttp(inner) => { @@ -259,7 +259,7 @@ impl Provider for AnyProvider { ) -> Result where B: AsRef + Send + Sync, - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { match self { Self::JsonRpcHttp(inner) => { @@ -276,10 +276,10 @@ impl Provider for AnyProvider { &self, block_id: B, contract_address: A, - ) -> Result + ) -> Result where B: AsRef + Send + Sync, - A: AsRef + Send + Sync, + A: AsRef + Send + Sync, { match self { Self::JsonRpcHttp(inner) => { @@ -308,7 +308,7 @@ impl Provider for AnyProvider { ) -> Result where B: AsRef + Send + Sync, - A: AsRef + Send + Sync, + A: AsRef + Send + Sync, { match self { Self::JsonRpcHttp(inner) => { @@ -348,7 +348,7 @@ impl Provider for AnyProvider { } } - async fn call(&self, request: R, block_id: B) -> Result, ProviderError> + async fn call(&self, request: R, block_id: B) -> Result, ProviderError> where R: AsRef + Send + Sync, B: AsRef + Send + Sync, @@ -443,7 +443,7 @@ impl Provider for AnyProvider { } } - async fn chain_id(&self) -> Result { + async fn chain_id(&self) -> Result { match self { Self::JsonRpcHttp(inner) => { as Provider>::chain_id(inner).await @@ -493,14 +493,10 @@ impl Provider for AnyProvider { } } - async fn get_nonce( - &self, - block_id: B, - contract_address: A, - ) -> Result + async fn get_nonce(&self, block_id: B, contract_address: A) -> Result where B: AsRef + Send + Sync, - A: AsRef + Send + Sync, + A: AsRef + Send + Sync, { match self { Self::JsonRpcHttp(inner) => { @@ -598,7 +594,7 @@ impl Provider for AnyProvider { transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { match self { Self::JsonRpcHttp(inner) => { diff --git a/starknet-providers/src/jsonrpc/mod.rs b/starknet-providers/src/jsonrpc/mod.rs index 324a25f1..ddb7e0d7 100644 --- a/starknet-providers/src/jsonrpc/mod.rs +++ b/starknet-providers/src/jsonrpc/mod.rs @@ -9,13 +9,13 @@ use starknet_core::{ requests::*, BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction, BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, BroadcastedTransaction, ContractClass, ContractErrorData, DeclareTransactionResult, DeployAccountTransactionResult, - EventFilter, EventFilterWithPage, EventsPage, FeeEstimate, FieldElement, FunctionCall, - InvokeTransactionResult, MaybePendingBlockWithReceipts, MaybePendingBlockWithTxHashes, - MaybePendingBlockWithTxs, MaybePendingStateUpdate, MsgFromL1, NoTraceAvailableErrorData, - ResultPageRequest, SimulatedTransaction, SimulationFlag, SimulationFlagForEstimateFee, - StarknetError, SyncStatusType, Transaction, TransactionExecutionErrorData, - TransactionReceiptWithBlockInfo, TransactionStatus, TransactionTrace, - TransactionTraceWithHash, + EventFilter, EventFilterWithPage, EventsPage, FeeEstimate, Felt as FeltPrimitive, + FunctionCall, InvokeTransactionResult, MaybePendingBlockWithReceipts, + MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate, + MsgFromL1, NoTraceAvailableErrorData, ResultPageRequest, SimulatedTransaction, + SimulationFlag, SimulationFlagForEstimateFee, StarknetError, SyncStatusType, Transaction, + TransactionExecutionErrorData, TransactionReceiptWithBlockInfo, TransactionStatus, + TransactionTrace, TransactionTraceWithHash, }, }; @@ -165,7 +165,7 @@ pub enum JsonRpcResponse { Error { id: u64, error: JsonRpcError }, } -/// Failures trying to parse a [JsonRpcError] into [StarknetError]. +/// Failures trying to parse a [`JsonRpcError`] into [`StarknetError`]. #[derive(Debug, thiserror::Error)] pub enum JsonRpcErrorConversionError { #[error("unknown error code")] @@ -178,14 +178,14 @@ pub enum JsonRpcErrorConversionError { #[serde_as] #[derive(Serialize, Deserialize)] -struct Felt(#[serde_as(as = "UfeHex")] pub FieldElement); +struct Felt(#[serde_as(as = "UfeHex")] pub FeltPrimitive); #[serde_as] #[derive(Serialize, Deserialize)] -struct FeltArray(#[serde_as(as = "Vec")] pub Vec); +struct FeltArray(#[serde_as(as = "Vec")] pub Vec); impl JsonRpcClient { - pub fn new(transport: T) -> Self { + pub const fn new(transport: T) -> Self { Self { transport } } } @@ -357,10 +357,10 @@ where contract_address: A, key: K, block_id: B, - ) -> Result + ) -> Result where - A: AsRef + Send + Sync, - K: AsRef + Send + Sync, + A: AsRef + Send + Sync, + K: AsRef + Send + Sync, B: AsRef + Send + Sync, { Ok(self @@ -383,7 +383,7 @@ where transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { self.send_request( JsonRpcMethod::GetTransactionStatus, @@ -400,7 +400,7 @@ where transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { self.send_request( JsonRpcMethod::GetTransactionByHash, @@ -436,7 +436,7 @@ where transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { self.send_request( JsonRpcMethod::GetTransactionReceipt, @@ -455,7 +455,7 @@ where ) -> Result where B: AsRef + Send + Sync, - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { self.send_request( JsonRpcMethod::GetClass, @@ -472,10 +472,10 @@ where &self, block_id: B, contract_address: A, - ) -> Result + ) -> Result where B: AsRef + Send + Sync, - A: AsRef + Send + Sync, + A: AsRef + Send + Sync, { Ok(self .send_request::<_, Felt>( @@ -497,7 +497,7 @@ where ) -> Result where B: AsRef + Send + Sync, - A: AsRef + Send + Sync, + A: AsRef + Send + Sync, { self.send_request( JsonRpcMethod::GetClassAt, @@ -524,7 +524,7 @@ where } /// Call a starknet function without creating a Starknet transaction - async fn call(&self, request: R, block_id: B) -> Result, ProviderError> + async fn call(&self, request: R, block_id: B) -> Result, ProviderError> where R: AsRef + Send + Sync, B: AsRef + Send + Sync, @@ -597,7 +597,7 @@ where } /// Return the currently configured Starknet chain id - async fn chain_id(&self) -> Result { + async fn chain_id(&self) -> Result { Ok(self .send_request::<_, Felt>(JsonRpcMethod::ChainId, ChainIdRequest) .await? @@ -637,10 +637,10 @@ where &self, block_id: B, contract_address: A, - ) -> Result + ) -> Result where B: AsRef + Send + Sync, - A: AsRef + Send + Sync, + A: AsRef + Send + Sync, { Ok(self .send_request::<_, Felt>( @@ -712,7 +712,7 @@ where transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { self.send_request( JsonRpcMethod::TraceTransaction, @@ -949,16 +949,16 @@ impl TryFrom<&JsonRpcError> for StarknetError { fn try_from(value: &JsonRpcError) -> Result { match value.code { - 1 => Ok(StarknetError::FailedToReceiveTransaction), - 20 => Ok(StarknetError::ContractNotFound), - 24 => Ok(StarknetError::BlockNotFound), - 27 => Ok(StarknetError::InvalidTransactionIndex), - 28 => Ok(StarknetError::ClassHashNotFound), - 29 => Ok(StarknetError::TransactionHashNotFound), - 31 => Ok(StarknetError::PageSizeTooBig), - 32 => Ok(StarknetError::NoBlocks), - 33 => Ok(StarknetError::InvalidContinuationToken), - 34 => Ok(StarknetError::TooManyKeysInFilter), + 1 => Ok(Self::FailedToReceiveTransaction), + 20 => Ok(Self::ContractNotFound), + 24 => Ok(Self::BlockNotFound), + 27 => Ok(Self::InvalidTransactionIndex), + 28 => Ok(Self::ClassHashNotFound), + 29 => Ok(Self::TransactionHashNotFound), + 31 => Ok(Self::PageSizeTooBig), + 32 => Ok(Self::NoBlocks), + 33 => Ok(Self::InvalidContinuationToken), + 34 => Ok(Self::TooManyKeysInFilter), 40 => { let data = ContractErrorData::deserialize( value @@ -967,7 +967,7 @@ impl TryFrom<&JsonRpcError> for StarknetError { .ok_or(JsonRpcErrorConversionError::MissingData)?, ) .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; - Ok(StarknetError::ContractError(data)) + Ok(Self::ContractError(data)) } 41 => { let data = TransactionExecutionErrorData::deserialize( @@ -977,12 +977,12 @@ impl TryFrom<&JsonRpcError> for StarknetError { .ok_or(JsonRpcErrorConversionError::MissingData)?, ) .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; - Ok(StarknetError::TransactionExecutionError(data)) + Ok(Self::TransactionExecutionError(data)) } - 51 => Ok(StarknetError::ClassAlreadyDeclared), - 52 => Ok(StarknetError::InvalidTransactionNonce), - 53 => Ok(StarknetError::InsufficientMaxFee), - 54 => Ok(StarknetError::InsufficientAccountBalance), + 51 => Ok(Self::ClassAlreadyDeclared), + 52 => Ok(Self::InvalidTransactionNonce), + 53 => Ok(Self::InsufficientMaxFee), + 54 => Ok(Self::InsufficientAccountBalance), 55 => { let data = String::deserialize( value @@ -991,15 +991,15 @@ impl TryFrom<&JsonRpcError> for StarknetError { .ok_or(JsonRpcErrorConversionError::MissingData)?, ) .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; - Ok(StarknetError::ValidationFailure(data)) + Ok(Self::ValidationFailure(data)) } - 56 => Ok(StarknetError::CompilationFailed), - 57 => Ok(StarknetError::ContractClassSizeIsTooLarge), - 58 => Ok(StarknetError::NonAccount), - 59 => Ok(StarknetError::DuplicateTx), - 60 => Ok(StarknetError::CompiledClassHashMismatch), - 61 => Ok(StarknetError::UnsupportedTxVersion), - 62 => Ok(StarknetError::UnsupportedContractClassVersion), + 56 => Ok(Self::CompilationFailed), + 57 => Ok(Self::ContractClassSizeIsTooLarge), + 58 => Ok(Self::NonAccount), + 59 => Ok(Self::DuplicateTx), + 60 => Ok(Self::CompiledClassHashMismatch), + 61 => Ok(Self::UnsupportedTxVersion), + 62 => Ok(Self::UnsupportedContractClassVersion), 63 => { let data = String::deserialize( value @@ -1008,7 +1008,7 @@ impl TryFrom<&JsonRpcError> for StarknetError { .ok_or(JsonRpcErrorConversionError::MissingData)?, ) .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; - Ok(StarknetError::UnexpectedError(data)) + Ok(Self::UnexpectedError(data)) } 10 => { let data = NoTraceAvailableErrorData::deserialize( @@ -1018,7 +1018,7 @@ impl TryFrom<&JsonRpcError> for StarknetError { .ok_or(JsonRpcErrorConversionError::MissingData)?, ) .map_err(|_| JsonRpcErrorConversionError::DataParsingFailure)?; - Ok(StarknetError::NoTraceAvailable(data)) + Ok(Self::NoTraceAvailable(data)) } _ => Err(JsonRpcErrorConversionError::UnknownCode), } diff --git a/starknet-providers/src/jsonrpc/transports/http.rs b/starknet-providers/src/jsonrpc/transports/http.rs index e5ce049a..450d6af8 100644 --- a/starknet-providers/src/jsonrpc/transports/http.rs +++ b/starknet-providers/src/jsonrpc/transports/http.rs @@ -40,8 +40,8 @@ impl HttpTransport { } } - /// Consumes the current [HttpTransport] instance and returns a new one with the header - /// appended. Same as calling [add_header]. + /// Consumes the current [`HttpTransport`] instance and returns a new one with the header + /// appended. Same as calling [`add_header`]. pub fn with_header(self, name: String, value: String) -> Self { let mut headers = self.headers; headers.push((name, value)); @@ -88,7 +88,7 @@ impl JsonRpcTransport for HttpTransport { .post(self.url.clone()) .body(request_body) .header("Content-Type", "application/json"); - for (name, value) in self.headers.iter() { + for (name, value) in &self.headers { request = request.header(name, value); } diff --git a/starknet-providers/src/provider.rs b/starknet-providers/src/provider.rs index c73448a7..efb2daf4 100644 --- a/starknet-providers/src/provider.rs +++ b/starknet-providers/src/provider.rs @@ -5,7 +5,7 @@ use starknet_core::types::{ BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction, BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, BroadcastedTransaction, ContractClass, DeclareTransactionResult, DeployAccountTransactionResult, EventFilter, - EventsPage, FeeEstimate, FieldElement, FunctionCall, InvokeTransactionResult, + EventsPage, FeeEstimate, Felt, FunctionCall, InvokeTransactionResult, MaybePendingBlockWithReceipts, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate, MsgFromL1, SimulatedTransaction, SimulationFlag, SimulationFlagForEstimateFee, StarknetError, SyncStatusType, Transaction, @@ -60,10 +60,10 @@ pub trait Provider { contract_address: A, key: K, block_id: B, - ) -> Result + ) -> Result where - A: AsRef + Send + Sync, - K: AsRef + Send + Sync, + A: AsRef + Send + Sync, + K: AsRef + Send + Sync, B: AsRef + Send + Sync; /// Gets the transaction status (possibly reflecting that the tx is still in @@ -73,7 +73,7 @@ pub trait Provider { transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync; + H: AsRef + Send + Sync; /// Get the details and status of a submitted transaction async fn get_transaction_by_hash( @@ -81,7 +81,7 @@ pub trait Provider { transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync; + H: AsRef + Send + Sync; /// Get the details of a transaction by a given block id and index async fn get_transaction_by_block_id_and_index( @@ -98,7 +98,7 @@ pub trait Provider { transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync; + H: AsRef + Send + Sync; /// Get the contract class definition in the given block associated with the given hash async fn get_class( @@ -108,17 +108,17 @@ pub trait Provider { ) -> Result where B: AsRef + Send + Sync, - H: AsRef + Send + Sync; + H: AsRef + Send + Sync; /// Get the contract class hash in the given block for the contract deployed at the given address async fn get_class_hash_at( &self, block_id: B, contract_address: A, - ) -> Result + ) -> Result where B: AsRef + Send + Sync, - A: AsRef + Send + Sync; + A: AsRef + Send + Sync; /// Get the contract class definition in the given block at the given address async fn get_class_at( @@ -128,7 +128,7 @@ pub trait Provider { ) -> Result where B: AsRef + Send + Sync, - A: AsRef + Send + Sync; + A: AsRef + Send + Sync; /// Get the number of transactions in a block given a block id async fn get_block_transaction_count(&self, block_id: B) -> Result @@ -136,7 +136,7 @@ pub trait Provider { B: AsRef + Send + Sync; /// Call a starknet function without creating a Starknet transaction - async fn call(&self, request: R, block_id: B) -> Result, ProviderError> + async fn call(&self, request: R, block_id: B) -> Result, ProviderError> where R: AsRef + Send + Sync, B: AsRef + Send + Sync; @@ -169,7 +169,7 @@ pub trait Provider { async fn block_hash_and_number(&self) -> Result; /// Return the currently configured Starknet chain id - async fn chain_id(&self) -> Result; + async fn chain_id(&self) -> Result; /// Returns an object about the sync status, or false if the node is not synching async fn syncing(&self) -> Result; @@ -187,10 +187,10 @@ pub trait Provider { &self, block_id: B, contract_address: A, - ) -> Result + ) -> Result where B: AsRef + Send + Sync, - A: AsRef + Send + Sync; + A: AsRef + Send + Sync; /// Submit a new transaction to be added to the chain async fn add_invoke_transaction( @@ -223,7 +223,7 @@ pub trait Provider { transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync; + H: AsRef + Send + Sync; /// Simulate a given sequence of transactions on the requested state, and generate the execution /// traces. Note that some of the transactions may revert, in which case no error is thrown, but @@ -320,10 +320,10 @@ pub trait Provider { /// Trait for implementation-specific error type. These errors are irrelevant in most cases, /// assuming that users typically care more about the specifics of RPC errors instead of the -/// underlying transport. Therefore, it makes little sense to bloat [ProviderError] with a generic +/// underlying transport. Therefore, it makes little sense to bloat [`ProviderError`] with a generic /// parameter just for these errors. Instead, they're erased to this trait object. /// -/// This trait is used instead of a plain [std::error::Error] to allow downcasting, in case access +/// This trait is used instead of a plain [`std::error::Error`] to allow downcasting, in case access /// to the specific error type is indeed desired. This is achieved with the `as_any()` method. pub trait ProviderImplError: Error + Debug + Send + Sync { fn as_any(&self) -> &dyn Any; diff --git a/starknet-providers/src/sequencer/mod.rs b/starknet-providers/src/sequencer/mod.rs index 3b06f121..b12c91e8 100644 --- a/starknet-providers/src/sequencer/mod.rs +++ b/starknet-providers/src/sequencer/mod.rs @@ -8,7 +8,7 @@ use serde_with::serde_as; use starknet_core::{ chain_id, serde::unsigned_field_element::UfeHex, - types::{contract::CompiledClass, FieldElement, StarknetError}, + types::{contract::CompiledClass, Felt, StarknetError}, }; use url::Url; @@ -25,7 +25,7 @@ pub struct SequencerGatewayProvider { client: Client, gateway_url: Url, feeder_gateway_url: Url, - chain_id: FieldElement, + chain_id: Felt, headers: Vec<(String, String)>, } @@ -37,7 +37,7 @@ pub enum GatewayClientError { /// JSON serialization/deserialization error #[error(transparent)] Serde(SerdeJsonError), - /// Sequencer error responses not parsable into [StarknetError] + /// Sequencer error responses not parsable into [`StarknetError`] #[error(transparent)] SequencerError(SequencerError), /// Method is not supported (only when using as [Provider]) @@ -103,7 +103,7 @@ impl SequencerGatewayProvider { pub fn new( gateway_url: impl Into, feeder_gateway_url: impl Into, - chain_id: FieldElement, + chain_id: Felt, ) -> Self { Self::new_with_client(gateway_url, feeder_gateway_url, chain_id, Client::new()) } @@ -111,7 +111,7 @@ impl SequencerGatewayProvider { pub fn new_with_client( gateway_url: impl Into, feeder_gateway_url: impl Into, - chain_id: FieldElement, + chain_id: Felt, client: Client, ) -> Self { Self { @@ -139,8 +139,8 @@ impl SequencerGatewayProvider { ) } - /// Consumes the current [SequencerGatewayProvider] instance and returns a new one with the - /// header appended. Same as calling [add_header]. + /// Consumes the current [`SequencerGatewayProvider`] instance and returns a new one with the + /// header appended. Same as calling [`add_header`]. pub fn with_header(self, name: String, value: String) -> Self { let mut headers = self.headers; headers.push((name, value)); @@ -165,18 +165,15 @@ enum GatewayResponse { SequencerError(SequencerError), } -// Work FieldElement deserialization +// Work Felt deserialization #[serde_as] #[derive(Deserialize)] #[serde(untagged)] enum RawFieldElementResponse { - Data(#[serde_as(as = "UfeHex")] FieldElement), + Data(#[serde_as(as = "UfeHex")] Felt), SequencerError(SequencerError), } -#[derive(Deserialize)] -struct EmptyObject {} - impl SequencerGatewayProvider { fn extend_gateway_url(&self, segment: &str) -> Url { let mut url = self.gateway_url.clone(); @@ -197,7 +194,7 @@ impl SequencerGatewayProvider { trace!("Sending GET request to sequencer API ({})", url); let mut request = self.client.get(url); - for (name, value) in self.headers.iter() { + for (name, value) in &self.headers { request = request.header(name, value); } @@ -231,7 +228,7 @@ impl SequencerGatewayProvider { .post(url) .header("Content-Type", "application/json") .body(request_body); - for (name, value) in self.headers.iter() { + for (name, value) in &self.headers { request = request.header(name, value); } @@ -316,12 +313,30 @@ impl SequencerGatewayProvider { .into() } + #[deprecated( + note = "Sequencer-specific functions are deprecated. Use it via the Provider trait instead." + )] + pub async fn get_state_update_with_block( + &self, + block_identifier: BlockId, + ) -> Result { + let mut request_url = self.extend_feeder_gateway_url("get_state_update"); + append_block_id(&mut request_url, block_identifier); + request_url + .query_pairs_mut() + .append_pair("includeBlock", "true"); + + self.send_get_request::>(request_url) + .await? + .into() + } + #[deprecated( note = "Sequencer-specific functions are deprecated. Use it via the Provider trait instead." )] pub async fn get_compiled_class_by_class_hash( &self, - class_hash: FieldElement, + class_hash: Felt, block_identifier: BlockId, ) -> Result { let mut request_url = self.extend_feeder_gateway_url("get_compiled_class_by_class_hash"); @@ -340,7 +355,7 @@ impl SequencerGatewayProvider { )] pub async fn get_class_by_hash( &self, - class_hash: FieldElement, + class_hash: Felt, block_identifier: BlockId, ) -> Result { let mut request_url = self.extend_feeder_gateway_url("get_class_by_hash"); @@ -359,7 +374,7 @@ impl SequencerGatewayProvider { )] pub async fn get_transaction_status( &self, - transaction_hash: FieldElement, + transaction_hash: Felt, ) -> Result { let mut request_url = self.extend_feeder_gateway_url("get_transaction_status"); request_url @@ -376,7 +391,7 @@ impl SequencerGatewayProvider { )] pub async fn get_transaction( &self, - transaction_hash: FieldElement, + transaction_hash: Felt, ) -> Result { let mut request_url = self.extend_feeder_gateway_url("get_transaction"); request_url @@ -393,7 +408,7 @@ impl SequencerGatewayProvider { )] pub async fn get_transaction_trace( &self, - transaction_hash: FieldElement, + transaction_hash: Felt, ) -> Result { let mut request_url = self.extend_feeder_gateway_url("get_transaction_trace"); request_url @@ -408,10 +423,7 @@ impl SequencerGatewayProvider { #[deprecated( note = "Sequencer-specific functions are deprecated. Use it via the Provider trait instead." )] - pub async fn get_block_hash_by_id( - &self, - block_number: u64, - ) -> Result { + pub async fn get_block_hash_by_id(&self, block_number: u64) -> Result { let mut request_url = self.extend_feeder_gateway_url("get_block_hash_by_id"); request_url .query_pairs_mut() @@ -425,10 +437,7 @@ impl SequencerGatewayProvider { #[deprecated( note = "Sequencer-specific functions are deprecated. Use it via the Provider trait instead." )] - pub async fn get_block_id_by_hash( - &self, - block_hash: FieldElement, - ) -> Result { + pub async fn get_block_id_by_hash(&self, block_hash: Felt) -> Result { let mut request_url = self.extend_feeder_gateway_url("get_block_id_by_hash"); request_url .query_pairs_mut() @@ -466,29 +475,27 @@ impl From for ProviderError { fn from(value: SequencerError) -> Self { let matching_code = match value.code { ErrorCode::BlockNotFound => Some(StarknetError::BlockNotFound), - ErrorCode::EntryPointNotFoundInContract => None, - ErrorCode::InvalidProgram => None, - ErrorCode::TransactionFailed => { + ErrorCode::EntryPointNotFoundInContract + | ErrorCode::InvalidContractClass + | ErrorCode::DeprecatedEndpoint + | ErrorCode::MalformedRequest + | ErrorCode::InvalidProgram => None, + ErrorCode::TransactionFailed | ErrorCode::ValidateFailure => { Some(StarknetError::ValidationFailure(value.message.clone())) } - ErrorCode::TransactionNotFound => Some(StarknetError::ContractNotFound), - ErrorCode::UninitializedContract => Some(StarknetError::ContractNotFound), - ErrorCode::MalformedRequest => None, + ErrorCode::TransactionNotFound | ErrorCode::UninitializedContract => { + Some(StarknetError::ContractNotFound) + } ErrorCode::UndeclaredClass => Some(StarknetError::ClassHashNotFound), ErrorCode::InvalidTransactionNonce => Some(StarknetError::InvalidTransactionNonce), - ErrorCode::ValidateFailure => { - Some(StarknetError::ValidationFailure(value.message.clone())) - } ErrorCode::ClassAlreadyDeclared => Some(StarknetError::ClassAlreadyDeclared), ErrorCode::CompilationFailed => Some(StarknetError::CompilationFailed), ErrorCode::InvalidCompiledClassHash => Some(StarknetError::CompiledClassHashMismatch), ErrorCode::DuplicatedTransaction => Some(StarknetError::DuplicateTx), - ErrorCode::InvalidContractClass => None, - ErrorCode::DeprecatedEndpoint => None, }; match matching_code { - Some(code) => ProviderError::StarknetError(code), + Some(code) => Self::StarknetError(code), None => GatewayClientError::SequencerError(value).into(), } } @@ -509,7 +516,7 @@ impl From> for Result { } } -impl From for Result { +impl From for Result { fn from(value: RawFieldElementResponse) -> Self { match value { RawFieldElementResponse::Data(data) => Ok(data), @@ -530,10 +537,10 @@ where { let temp_value = serde_json::Value::deserialize(deserializer)?; if let Ok(value) = T::deserialize(&temp_value) { - return Ok(GatewayResponse::Data(value)); + return Ok(Self::Data(value)); } if let Ok(value) = SequencerError::deserialize(&temp_value) { - return Ok(GatewayResponse::SequencerError(value)); + return Ok(Self::SequencerError(value)); } Err(serde::de::Error::custom( "data did not match any variant of enum GatewayResponse", @@ -574,9 +581,7 @@ mod tests { for raw in [ include_str!("../../test-data/raw_gateway_responses/get_class_by_hash/1_cairo_0.txt"), include_str!("../../test-data/raw_gateway_responses/get_class_by_hash/3_cairo_1.txt"), - ] - .into_iter() - { + ] { serde_json::from_str::>(raw).unwrap(); } } diff --git a/starknet-providers/src/sequencer/models/block.rs b/starknet-providers/src/sequencer/models/block.rs index 2a0bd3a9..75430a51 100644 --- a/starknet-providers/src/sequencer/models/block.rs +++ b/starknet-providers/src/sequencer/models/block.rs @@ -2,14 +2,14 @@ use serde::Deserialize; use serde_with::serde_as; use starknet_core::{ serde::unsigned_field_element::{UfeHex, UfeHexOption}, - types::{FieldElement, L1DataAvailabilityMode, ResourcePrice}, + types::{Felt, L1DataAvailabilityMode, ResourcePrice}, }; use super::{ConfirmedTransactionReceipt, TransactionType}; #[derive(Debug, Clone, Copy)] pub enum BlockId { - Hash(FieldElement), + Hash(Felt), Number(u64), Pending, Latest, @@ -37,24 +37,24 @@ pub enum BlockStatus { pub struct Block { #[serde(default)] #[serde_as(as = "UfeHexOption")] - pub block_hash: Option, + pub block_hash: Option, pub block_number: Option, #[serde_as(as = "UfeHex")] - pub parent_block_hash: FieldElement, + pub parent_block_hash: Felt, pub timestamp: u64, // Field marked optional as old blocks don't include it yet. Drop optional once resolved. #[serde(default)] #[serde_as(as = "UfeHexOption")] - pub sequencer_address: Option, + pub sequencer_address: Option, #[serde(default)] #[serde_as(as = "UfeHexOption")] - pub state_root: Option, + pub state_root: Option, #[serde(default)] #[serde_as(as = "UfeHexOption")] - pub transaction_commitment: Option, + pub transaction_commitment: Option, #[serde(default)] #[serde_as(as = "UfeHexOption")] - pub event_commitment: Option, + pub event_commitment: Option, pub status: BlockStatus, pub l1_da_mode: L1DataAvailabilityMode, pub l1_gas_price: ResourcePrice, @@ -82,24 +82,18 @@ mod tests { assert_eq!(block.status, BlockStatus::AcceptedOnL1); assert_eq!( block.state_root.unwrap(), - FieldElement::from_hex_be( - "051098918fd96edda4e251f695181c063e21fb0666352e3469db507c7fd62b89" - ) - .unwrap() + Felt::from_hex("051098918fd96edda4e251f695181c063e21fb0666352e3469db507c7fd62b89") + .unwrap() ); assert_eq!( block.transaction_commitment.unwrap(), - FieldElement::from_hex_be( - "0576db32d35cf011694a73c6ce400d5d77f768cbd77ee7cf87d12902e0f9b4ec" - ) - .unwrap() + Felt::from_hex("0576db32d35cf011694a73c6ce400d5d77f768cbd77ee7cf87d12902e0f9b4ec") + .unwrap() ); assert_eq!( block.event_commitment.unwrap(), - FieldElement::from_hex_be( - "01c972780140fd16dde94639226ca25818e4f24ecd5b5c3065cc1f5f5fc410f9" - ) - .unwrap() + Felt::from_hex("01c972780140fd16dde94639226ca25818e4f24ecd5b5c3065cc1f5f5fc410f9") + .unwrap() ); assert_eq!(block.transactions.len(), 4); assert_eq!(block.transaction_receipts.len(), 4); @@ -219,10 +213,8 @@ mod tests { assert_eq!( tx.sender_address, - FieldElement::from_hex_be( - "0x68922eb87daed71fc3099031e178b6534fc39a570022342e8c166024da893f5" - ) - .unwrap() + Felt::from_hex("0x68922eb87daed71fc3099031e178b6534fc39a570022342e8c166024da893f5") + .unwrap() ); } @@ -242,10 +234,8 @@ mod tests { assert_eq!( tx.contract_address, - FieldElement::from_hex_be( - "0x4c5772d1914fe6ce891b64eb35bf3522aeae1315647314aac58b01137607f3f" - ) - .unwrap() + Felt::from_hex("0x4c5772d1914fe6ce891b64eb35bf3522aeae1315647314aac58b01137607f3f") + .unwrap() ); } diff --git a/starknet-providers/src/sequencer/models/contract.rs b/starknet-providers/src/sequencer/models/contract.rs index bfeb7d31..0ef6a2e6 100644 --- a/starknet-providers/src/sequencer/models/contract.rs +++ b/starknet-providers/src/sequencer/models/contract.rs @@ -10,7 +10,7 @@ use starknet_core::{ legacy::{LegacyContractClass, RawLegacyAbiEntry, RawLegacyEntryPoints}, CompressProgramError, }, - EntryPointsByType, FieldElement, FlattenedSierraClass, + EntryPointsByType, Felt, FlattenedSierraClass, }, }; @@ -78,7 +78,7 @@ impl CompressedSierraClass { ) -> Result { #[serde_as] #[derive(Serialize)] - struct SierraProgram<'a>(#[serde_as(as = "Vec")] &'a Vec); + struct SierraProgram<'a>(#[serde_as(as = "Vec")] &'a Vec); let program_json = serde_json::to_string(&SierraProgram(&flattened_class.sierra_program)) .map_err(DecompressProgramError::Json)?; @@ -91,7 +91,7 @@ impl CompressedSierraClass { let compressed_program = gzip_encoder.finish().map_err(DecompressProgramError::Io)?; - Ok(CompressedSierraClass { + Ok(Self { sierra_program: compressed_program, contract_class_version: flattened_class.contract_class_version.clone(), entry_points_by_type: flattened_class.entry_points_by_type.clone(), diff --git a/starknet-providers/src/sequencer/models/conversions.rs b/starknet-providers/src/sequencer/models/conversions.rs index e6358fd2..6af9f96a 100644 --- a/starknet-providers/src/sequencer/models/conversions.rs +++ b/starknet-providers/src/sequencer/models/conversions.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use starknet_core::types::{self as core, contract::legacy as contract_legacy, FieldElement}; +use starknet_core::types::{self as core, contract::legacy as contract_legacy, Felt}; use super::{ state_update::{DeclaredContract, DeployedContract, StateDiff, StorageDiff}, @@ -24,7 +24,7 @@ pub(crate) struct ConfirmedReceiptWithContext { pub(crate) struct OrderedL2ToL1MessageResponseWithFromAddress { pub message: OrderedL2ToL1MessageResponse, - pub from: FieldElement, + pub from: Felt, } impl From for BlockId { @@ -228,7 +228,7 @@ impl TryFrom for core::DeclareTransaction { type Error = ConversionError; fn try_from(value: DeclareTransaction) -> Result { - if value.version == FieldElement::ZERO { + if value.version == Felt::ZERO { Ok(Self::V0(core::DeclareTransactionV0 { transaction_hash: value.transaction_hash, max_fee: value.max_fee.ok_or(ConversionError)?, @@ -236,7 +236,7 @@ impl TryFrom for core::DeclareTransaction { class_hash: value.class_hash, sender_address: value.sender_address, })) - } else if value.version == FieldElement::ONE { + } else if value.version == Felt::ONE { Ok(Self::V1(core::DeclareTransactionV1 { transaction_hash: value.transaction_hash, max_fee: value.max_fee.ok_or(ConversionError)?, @@ -245,7 +245,7 @@ impl TryFrom for core::DeclareTransaction { class_hash: value.class_hash, sender_address: value.sender_address, })) - } else if value.version == FieldElement::TWO { + } else if value.version == Felt::TWO { Ok(Self::V2(core::DeclareTransactionV2 { transaction_hash: value.transaction_hash, max_fee: value.max_fee.ok_or(ConversionError)?, @@ -255,7 +255,7 @@ impl TryFrom for core::DeclareTransaction { compiled_class_hash: value.compiled_class_hash.ok_or(ConversionError)?, sender_address: value.sender_address, })) - } else if value.version == FieldElement::THREE { + } else if value.version == Felt::THREE { Ok(Self::V3(core::DeclareTransactionV3 { transaction_hash: value.transaction_hash, sender_address: value.sender_address, @@ -300,7 +300,7 @@ impl TryFrom for core::DeployAccountTransaction { type Error = ConversionError; fn try_from(value: DeployAccountTransaction) -> Result { - if value.version == FieldElement::ONE { + if value.version == Felt::ONE { Ok(Self::V1(core::DeployAccountTransactionV1 { transaction_hash: value.transaction_hash, max_fee: value.max_fee.ok_or(ConversionError)?, @@ -310,7 +310,7 @@ impl TryFrom for core::DeployAccountTransaction { constructor_calldata: value.constructor_calldata, class_hash: value.class_hash, })) - } else if value.version == FieldElement::THREE { + } else if value.version == Felt::THREE { Ok(Self::V3(core::DeployAccountTransactionV3 { transaction_hash: value.transaction_hash, signature: value.signature, @@ -340,7 +340,7 @@ impl TryFrom for core::InvokeTransaction { type Error = ConversionError; fn try_from(value: InvokeFunctionTransaction) -> Result { - if value.version == FieldElement::ZERO { + if value.version == Felt::ZERO { Ok(Self::V0(core::InvokeTransactionV0 { transaction_hash: value.transaction_hash, max_fee: value.max_fee.ok_or(ConversionError)?, @@ -349,7 +349,7 @@ impl TryFrom for core::InvokeTransaction { entry_point_selector: value.entry_point_selector.ok_or(ConversionError)?, calldata: value.calldata, })) - } else if value.version == FieldElement::ONE { + } else if value.version == Felt::ONE { Ok(Self::V1(core::InvokeTransactionV1 { transaction_hash: value.transaction_hash, max_fee: value.max_fee.ok_or(ConversionError)?, @@ -358,7 +358,7 @@ impl TryFrom for core::InvokeTransaction { sender_address: value.sender_address, calldata: value.calldata, })) - } else if value.version == FieldElement::THREE { + } else if value.version == Felt::THREE { Ok(Self::V3(core::InvokeTransactionV3 { transaction_hash: value.transaction_hash, sender_address: value.sender_address, @@ -391,11 +391,14 @@ impl TryFrom for core::L1HandlerTransaction { Ok(Self { transaction_hash: value.transaction_hash, version: value.version, - nonce: value - .nonce - .unwrap_or_default() - .try_into() - .map_err(|_| ConversionError)?, + nonce: { + // TODO: remove this when a proper u64 conversion is implemented for `Felt` + let nonce_bytes = value.nonce.unwrap_or_default().to_bytes_le(); + if nonce_bytes.iter().skip(8).any(|&x| x != 0) { + return Err(ConversionError); + } + u64::from_le_bytes(nonce_bytes[..8].try_into().unwrap()) + }, contract_address: value.contract_address, entry_point_selector: value.entry_point_selector, calldata: value.calldata, @@ -568,7 +571,7 @@ impl From for core::MsgToL1 { Self { from_address: value.from_address, // Unwrapping here is safe - to_address: FieldElement::from_byte_slice_be(&value.to_address.0).unwrap(), + to_address: Felt::from_bytes_be_slice(&value.to_address.0), payload: value.payload, } } @@ -601,8 +604,9 @@ impl TryFrom for core::TransactionFinalityStatus { fn try_from(value: TransactionFinalityStatus) -> Result { match value { - TransactionFinalityStatus::NotReceived => Err(ConversionError), - TransactionFinalityStatus::Received => Err(ConversionError), + TransactionFinalityStatus::NotReceived | TransactionFinalityStatus::Received => { + Err(ConversionError) + } TransactionFinalityStatus::AcceptedOnL2 => Ok(Self::AcceptedOnL2), TransactionFinalityStatus::AcceptedOnL1 => Ok(Self::AcceptedOnL1), } @@ -871,10 +875,7 @@ impl From for core::OrderedMessage Self { from_address: value.from, // Unwrapping is safe here as H160 is only 20 bytes - to_address: FieldElement::from_byte_slice_be( - &value.message.to_address.to_fixed_bytes(), - ) - .unwrap(), + to_address: Felt::from_bytes_be_slice(&value.message.to_address.to_fixed_bytes()), payload: value.message.payload, order: value.message.order, } @@ -902,7 +903,7 @@ impl TryFrom for core::TransactionStatus { type Error = ConversionError; fn try_from(value: TransactionStatusInfo) -> Result { - if let TransactionStatus::Rejected = value.status { + if value.status.is_rejected() { return Ok(Self::Rejected); } @@ -1209,7 +1210,7 @@ fn convert_execution_result( } } -fn convert_legacy_entry_point( +const fn convert_legacy_entry_point( value: core::LegacyContractEntryPoint, ) -> contract_legacy::RawLegacyEntryPoint { // WARNING: this causes pre-0.11.0 contract declaration to fail due to `offset` issue diff --git a/starknet-providers/src/sequencer/models/mod.rs b/starknet-providers/src/sequencer/models/mod.rs index 3e269958..c1c0922e 100644 --- a/starknet-providers/src/sequencer/models/mod.rs +++ b/starknet-providers/src/sequencer/models/mod.rs @@ -46,7 +46,7 @@ mod contract; pub use contract::{CompressedLegacyContractClass, DeployedClass}; pub mod state_update; -pub use state_update::StateUpdate; +pub use state_update::{StateUpdate, StateUpdateWithBlock}; pub mod trace; pub use trace::{BlockTraces, TransactionTrace}; diff --git a/starknet-providers/src/sequencer/models/serde_impls.rs b/starknet-providers/src/sequencer/models/serde_impls.rs index f54d344f..fda5b8e7 100644 --- a/starknet-providers/src/sequencer/models/serde_impls.rs +++ b/starknet-providers/src/sequencer/models/serde_impls.rs @@ -20,7 +20,7 @@ pub(crate) mod u64_hex { impl<'de> Visitor<'de> for U64HexVisitor { type Value = u64; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "string") } @@ -56,7 +56,7 @@ pub(crate) mod u128_hex { impl<'de> Visitor<'de> for U128HexVisitor { type Value = u128; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "string") } @@ -95,7 +95,7 @@ pub(crate) mod u64_hex_opt { impl<'de> Visitor<'de> for U64HexOptVisitor { type Value = Option; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "null or string") } diff --git a/starknet-providers/src/sequencer/models/state_update.rs b/starknet-providers/src/sequencer/models/state_update.rs index 18cd5ee9..c0e56316 100644 --- a/starknet-providers/src/sequencer/models/state_update.rs +++ b/starknet-providers/src/sequencer/models/state_update.rs @@ -1,18 +1,28 @@ use serde::Deserialize; use serde_with::serde_as; -use starknet_core::{serde::unsigned_field_element::UfeHex, types::FieldElement}; +use starknet_core::{serde::unsigned_field_element::UfeHex, types::Felt}; use std::collections::HashMap; +use super::Block; + +#[serde_as] +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] +pub struct StateUpdateWithBlock { + pub state_update: StateUpdate, + pub block: Block, +} + #[serde_as] #[derive(Debug, Deserialize)] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct StateUpdate { #[serde_as(as = "Option")] - pub block_hash: Option, + pub block_hash: Option, #[serde_as(as = "Option")] - pub new_root: Option, + pub new_root: Option, #[serde_as(as = "UfeHex")] - pub old_root: FieldElement, + pub old_root: Felt, pub state_diff: StateDiff, } @@ -21,14 +31,14 @@ pub struct StateUpdate { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct StateDiff { #[serde_as(as = "HashMap")] - pub storage_diffs: HashMap>, + pub storage_diffs: HashMap>, pub deployed_contracts: Vec, #[serde_as(as = "Vec")] - pub old_declared_contracts: Vec, + pub old_declared_contracts: Vec, pub declared_classes: Vec, #[serde(default)] #[serde_as(as = "HashMap")] - pub nonces: HashMap, + pub nonces: HashMap, pub replaced_classes: Vec, } @@ -37,9 +47,9 @@ pub struct StateDiff { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct StorageDiff { #[serde_as(as = "UfeHex")] - pub key: FieldElement, + pub key: Felt, #[serde_as(as = "UfeHex")] - pub value: FieldElement, + pub value: Felt, } #[serde_as] @@ -47,9 +57,9 @@ pub struct StorageDiff { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct DeployedContract { #[serde_as(as = "UfeHex")] - pub address: FieldElement, + pub address: Felt, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, } #[serde_as] @@ -57,9 +67,9 @@ pub struct DeployedContract { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct DeclaredContract { #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, #[serde_as(as = "UfeHex")] - pub compiled_class_hash: FieldElement, + pub compiled_class_hash: Felt, } #[cfg(test)] @@ -78,7 +88,7 @@ mod tests { .state_diff .storage_diffs .get( - &FieldElement::from_hex_be( + &Felt::from_hex( "0x197b9913e67947b0605934ec72db497d341a0199282c1da6d4aae46b17e0e76", ) .unwrap(), @@ -87,17 +97,13 @@ mod tests { assert_eq!( storage_diff.key, - FieldElement::from_hex_be( - "0x34c0d833897dbc937dd35e9f49a5184aecd6ab47829de999f9587549f82d0e" - ) - .unwrap() + Felt::from_hex("0x34c0d833897dbc937dd35e9f49a5184aecd6ab47829de999f9587549f82d0e") + .unwrap() ); assert_eq!( storage_diff.value, - FieldElement::from_hex_be( - "0x74fd8ca6e84097ad9ae00febfb690ad032fc4477155ec2193382c1b30b5e12b" - ) - .unwrap() + Felt::from_hex("0x74fd8ca6e84097ad9ae00febfb690ad032fc4477155ec2193382c1b30b5e12b") + .unwrap() ); } diff --git a/starknet-providers/src/sequencer/models/trace.rs b/starknet-providers/src/sequencer/models/trace.rs index 680e6072..cce9ec2f 100644 --- a/starknet-providers/src/sequencer/models/trace.rs +++ b/starknet-providers/src/sequencer/models/trace.rs @@ -1,6 +1,6 @@ use serde::Deserialize; use serde_with::serde_as; -use starknet_core::{serde::unsigned_field_element::UfeHex, types::FieldElement}; +use starknet_core::{serde::unsigned_field_element::UfeHex, types::Felt}; use super::{EntryPointType, ExecutionResources, L1Address}; @@ -28,7 +28,7 @@ pub struct TransactionTrace { #[serde(default)] pub validate_invocation: Option, #[serde_as(as = "Vec")] - pub signature: Vec, + pub signature: Vec, } #[serde_as] @@ -38,7 +38,7 @@ pub struct TransactionTraceWithHash { #[serde(flatten)] pub trace: TransactionTrace, #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, } #[derive(Debug, Deserialize, PartialEq, Eq)] @@ -55,23 +55,23 @@ pub enum CallType { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct FunctionInvocation { #[serde_as(as = "UfeHex")] - pub caller_address: FieldElement, + pub caller_address: Felt, #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, #[serde_as(as = "Vec")] - pub calldata: Vec, + pub calldata: Vec, pub call_type: Option, // This field is marked optional because it's missing from old transactions. Drop `Option` once // it's resolved. #[serde_as(as = "Option")] - pub class_hash: Option, + pub class_hash: Option, // This field is marked optional because it's missing from old transactions. Drop `Option` once // it's resolved. #[serde_as(as = "Option")] - pub selector: Option, + pub selector: Option, pub entry_point_type: Option, #[serde_as(as = "Vec")] - pub result: Vec, + pub result: Vec, pub execution_resources: ExecutionResources, pub internal_calls: Vec, pub events: Vec, @@ -84,9 +84,9 @@ pub struct FunctionInvocation { pub struct OrderedEventResponse { pub order: u64, #[serde_as(as = "Vec")] - pub keys: Vec, + pub keys: Vec, #[serde_as(as = "Vec")] - pub data: Vec, + pub data: Vec, } #[serde_as] @@ -96,7 +96,7 @@ pub struct OrderedL2ToL1MessageResponse { pub order: u64, pub to_address: L1Address, #[serde_as(as = "Vec")] - pub payload: Vec, + pub payload: Vec, } #[cfg(test)] diff --git a/starknet-providers/src/sequencer/models/transaction.rs b/starknet-providers/src/sequencer/models/transaction.rs index e6bc531d..75aaa0b6 100644 --- a/starknet-providers/src/sequencer/models/transaction.rs +++ b/starknet-providers/src/sequencer/models/transaction.rs @@ -2,7 +2,7 @@ use serde::{de::Visitor, Deserialize, Serialize}; use serde_with::serde_as; use starknet_core::{ serde::unsigned_field_element::{UfeHex, UfePendingBlockHash}, - types::FieldElement, + types::Felt, }; use super::{ @@ -28,7 +28,7 @@ pub enum TransactionType { pub struct TransactionStatusInfo { #[serde(default)] #[serde_as(as = "UfePendingBlockHash")] - pub block_hash: Option, + pub block_hash: Option, #[serde(alias = "tx_status")] pub status: TransactionStatus, // This field is actually always present since v0.12.1, but we're keeping it optional until @@ -56,7 +56,7 @@ pub struct TransactionFailureReason { pub struct TransactionInfo { #[serde(default)] #[serde_as(as = "UfePendingBlockHash")] - pub block_hash: Option, + pub block_hash: Option, pub block_number: Option, pub status: TransactionStatus, // This field is actually always present since v0.12.1, but we're keeping it optional until @@ -87,31 +87,31 @@ pub enum EntryPointType { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct DeclareTransaction { #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, #[serde_as(as = "Option")] - pub compiled_class_hash: Option, + pub compiled_class_hash: Option, #[serde_as(as = "UfeHex")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, #[serde(default)] #[serde_as(as = "Option")] - pub max_fee: Option, + pub max_fee: Option, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, #[serde_as(deserialize_as = "Vec")] - pub signature: Vec, + pub signature: Vec, pub nonce_data_availability_mode: Option, pub fee_data_availability_mode: Option, pub resource_bounds: Option, #[serde(default, with = "u64_hex_opt")] pub tip: Option, #[serde_as(as = "Option>")] - pub paymaster_data: Option>, + pub paymaster_data: Option>, #[serde_as(deserialize_as = "Option>")] - pub account_deployment_data: Option>, + pub account_deployment_data: Option>, } #[serde_as] @@ -119,17 +119,17 @@ pub struct DeclareTransaction { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct DeployTransaction { #[serde_as(deserialize_as = "Vec")] - pub constructor_calldata: Vec, + pub constructor_calldata: Vec, #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, #[serde_as(as = "UfeHex")] - pub contract_address_salt: FieldElement, + pub contract_address_salt: Felt, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, } #[serde_as] @@ -137,35 +137,35 @@ pub struct DeployTransaction { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct DeployAccountTransaction { #[serde_as(deserialize_as = "Vec")] - pub constructor_calldata: Vec, + pub constructor_calldata: Vec, #[serde(default)] #[serde_as(as = "Option")] - pub contract_address: Option, + pub contract_address: Option, #[serde_as(as = "UfeHex")] - pub contract_address_salt: FieldElement, + pub contract_address_salt: Felt, #[serde_as(as = "UfeHex")] - pub class_hash: FieldElement, + pub class_hash: Felt, #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, #[serde_as(as = "UfeHex")] - pub nonce: FieldElement, + pub nonce: Felt, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, #[serde_as(deserialize_as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde(default)] #[serde_as(as = "Option")] - pub max_fee: Option, + pub max_fee: Option, pub nonce_data_availability_mode: Option, pub fee_data_availability_mode: Option, pub resource_bounds: Option, #[serde(default, with = "u64_hex_opt")] pub tip: Option, #[serde_as(as = "Option>")] - pub paymaster_data: Option>, + pub paymaster_data: Option>, #[serde(default)] #[serde_as(as = "Option")] - pub sender_address: Option, + pub sender_address: Option, } #[serde_as] @@ -175,31 +175,31 @@ pub struct InvokeFunctionTransaction { #[serde_as(as = "UfeHex")] // Need this alias because older blocks still use `contract_address` #[serde(alias = "contract_address")] - pub sender_address: FieldElement, + pub sender_address: Felt, #[serde_as(as = "Option")] - pub entry_point_selector: Option, + pub entry_point_selector: Option, #[serde_as(deserialize_as = "Vec")] - pub calldata: Vec, + pub calldata: Vec, #[serde_as(deserialize_as = "Vec")] - pub signature: Vec, + pub signature: Vec, #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, #[serde(default)] #[serde_as(as = "Option")] - pub max_fee: Option, + pub max_fee: Option, #[serde_as(as = "Option")] - pub nonce: Option, + pub nonce: Option, pub nonce_data_availability_mode: Option, pub fee_data_availability_mode: Option, pub resource_bounds: Option, #[serde(default, with = "u64_hex_opt")] pub tip: Option, #[serde_as(as = "Option>")] - pub paymaster_data: Option>, + pub paymaster_data: Option>, #[serde_as(deserialize_as = "Option>")] - pub account_deployment_data: Option>, + pub account_deployment_data: Option>, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, } #[serde_as] @@ -207,17 +207,17 @@ pub struct InvokeFunctionTransaction { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct L1HandlerTransaction { #[serde_as(as = "UfeHex")] - pub contract_address: FieldElement, + pub contract_address: Felt, #[serde_as(as = "UfeHex")] - pub entry_point_selector: FieldElement, + pub entry_point_selector: Felt, #[serde_as(deserialize_as = "Vec")] - pub calldata: Vec, + pub calldata: Vec, #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, #[serde_as(as = "Option")] - pub nonce: Option, + pub nonce: Option, #[serde_as(as = "UfeHex")] - pub version: FieldElement, + pub version: Felt, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -246,13 +246,13 @@ pub enum DataAvailabilityMode { struct DataAvailabilityModeVisitor; impl TransactionType { - pub fn transaction_hash(&self) -> FieldElement { + pub const fn transaction_hash(&self) -> Felt { match self { - TransactionType::Declare(inner) => inner.transaction_hash, - TransactionType::Deploy(inner) => inner.transaction_hash, - TransactionType::DeployAccount(inner) => inner.transaction_hash, - TransactionType::InvokeFunction(inner) => inner.transaction_hash, - TransactionType::L1Handler(inner) => inner.transaction_hash, + Self::Declare(inner) => inner.transaction_hash, + Self::Deploy(inner) => inner.transaction_hash, + Self::DeployAccount(inner) => inner.transaction_hash, + Self::InvokeFunction(inner) => inner.transaction_hash, + Self::L1Handler(inner) => inner.transaction_hash, } } } @@ -281,7 +281,7 @@ impl<'de> Deserialize<'de> for DataAvailabilityMode { impl<'de> Visitor<'de> for DataAvailabilityModeVisitor { type Value = DataAvailabilityMode; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "integer") } @@ -344,7 +344,7 @@ mod tests { let tx: TransactionInfo = serde_json::from_str(raw).unwrap(); assert_eq!(tx.block_number, None); - assert_eq!(tx.status, TransactionStatus::NotReceived); + assert!(tx.status.is_not_received()); } #[test] @@ -412,7 +412,7 @@ mod tests { match tx.r#type.unwrap() { TransactionType::InvokeFunction(tx) => { - assert_eq!(tx.version, FieldElement::THREE); + assert_eq!(tx.version, Felt::THREE); } _ => panic!("Did not deserialize TransactionType::InvokeFunction properly"), } @@ -428,7 +428,7 @@ mod tests { match tx.r#type.unwrap() { TransactionType::Declare(tx) => { - assert_eq!(tx.version, FieldElement::THREE); + assert_eq!(tx.version, Felt::THREE); } _ => panic!("Did not deserialize TransactionType::Declare properly"), } @@ -444,7 +444,7 @@ mod tests { match tx.r#type.unwrap() { TransactionType::DeployAccount(tx) => { - assert_eq!(tx.version, FieldElement::THREE); + assert_eq!(tx.version, Felt::THREE); } _ => panic!("Did not deserialize TransactionType::DeployAccount properly"), } @@ -459,14 +459,12 @@ mod tests { let tx: TransactionStatusInfo = serde_json::from_str(raw).unwrap(); - assert_eq!(tx.status, TransactionStatus::AcceptedOnL1); + assert!(tx.status.is_accepted_on_l1()); assert_eq!( tx.block_hash, Some( - FieldElement::from_hex_be( - "0x13b390a0b2c48f907cda28c73a12aa31b96d51bc1be004ba5f71174d8d70e4f" - ) - .unwrap() + Felt::from_hex("0x13b390a0b2c48f907cda28c73a12aa31b96d51bc1be004ba5f71174d8d70e4f") + .unwrap() ) ); } @@ -480,7 +478,7 @@ mod tests { let tx: TransactionStatusInfo = serde_json::from_str(raw).unwrap(); - assert_eq!(tx.status, TransactionStatus::NotReceived); + assert!(tx.status.is_not_received()); assert!(tx.block_hash.is_none()); } @@ -494,7 +492,7 @@ mod tests { let tx: TransactionStatusInfo = serde_json::from_str(raw).unwrap(); - assert_eq!(tx.status, TransactionStatus::Rejected); + assert!(tx.status.is_rejected()); assert!(tx.block_hash.is_none()); assert!(tx.transaction_failure_reason.is_some()); } diff --git a/starknet-providers/src/sequencer/models/transaction_receipt.rs b/starknet-providers/src/sequencer/models/transaction_receipt.rs index 356586a4..97f6e864 100644 --- a/starknet-providers/src/sequencer/models/transaction_receipt.rs +++ b/starknet-providers/src/sequencer/models/transaction_receipt.rs @@ -1,8 +1,9 @@ use serde::Deserialize; use serde_with::serde_as; + use starknet_core::{ serde::unsigned_field_element::{UfeHex, UfePendingBlockHash}, - types::{DataAvailabilityResources, FieldElement}, + types::{DataAvailabilityResources, Felt}, }; use super::{L1Address, TransactionFailureReason}; @@ -12,7 +13,7 @@ use super::{L1Address, TransactionFailureReason}; #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct ConfirmedReceipt { #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, pub transaction_index: u64, // This field is actually always present since v0.12.1, but we're keeping it optional until // mainnet is upgraded. @@ -26,7 +27,7 @@ pub struct ConfirmedReceipt { pub l2_to_l1_messages: Vec, pub events: Vec, #[serde_as(as = "UfeHex")] - pub actual_fee: FieldElement, + pub actual_fee: Felt, } #[derive(Debug, Deserialize, PartialEq, Eq)] @@ -49,6 +50,43 @@ pub enum TransactionStatus { AcceptedOnL1, } +impl TransactionStatus { + /// Returns `true` if the transaction status is `NotReceived`. + pub const fn is_not_received(&self) -> bool { + matches!(self, Self::NotReceived) + } + + /// Returns `true` if the transaction status is `Received`. + pub const fn is_received(&self) -> bool { + matches!(self, Self::Received) + } + + /// Returns `true` if the transaction status is `Pending`. + pub const fn is_pending(&self) -> bool { + matches!(self, Self::Pending) + } + + /// Returns `true` if the transaction status is `Rejected`. + pub const fn is_rejected(&self) -> bool { + matches!(self, Self::Rejected) + } + + /// Returns `true` if the transaction status is `Reverted`. + pub const fn is_reverted(&self) -> bool { + matches!(self, Self::Reverted) + } + + /// Returns `true` if the transaction status is `AcceptedOnL2`. + pub const fn is_accepted_on_l2(&self) -> bool { + matches!(self, Self::AcceptedOnL2) + } + + /// Returns `true` if the transaction status is `AcceptedOnL1`. + pub const fn is_accepted_on_l1(&self) -> bool { + matches!(self, Self::AcceptedOnL1) + } +} + #[derive(Debug, Deserialize, PartialEq, Eq)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] @@ -97,13 +135,13 @@ pub struct BuiltinInstanceCounter { pub struct L1ToL2Message { pub from_address: L1Address, #[serde_as(as = "UfeHex")] - pub to_address: FieldElement, + pub to_address: Felt, #[serde_as(deserialize_as = "UfeHex")] - pub selector: FieldElement, + pub selector: Felt, #[serde_as(deserialize_as = "Vec")] - pub payload: Vec, + pub payload: Vec, #[serde_as(deserialize_as = "Option")] - pub nonce: Option, + pub nonce: Option, } #[serde_as] @@ -111,10 +149,10 @@ pub struct L1ToL2Message { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct L2ToL1Message { #[serde_as(as = "UfeHex")] - pub from_address: FieldElement, + pub from_address: Felt, pub to_address: L1Address, #[serde_as(deserialize_as = "Vec")] - pub payload: Vec, + pub payload: Vec, } #[serde_as] @@ -122,9 +160,9 @@ pub struct L2ToL1Message { #[cfg_attr(feature = "no_unknown_fields", serde(deny_unknown_fields))] pub struct Event { #[serde_as(as = "UfeHex")] - pub from_address: FieldElement, + pub from_address: Felt, #[serde_as(deserialize_as = "Vec")] - pub keys: Vec, + pub keys: Vec, #[serde_as(deserialize_as = "Vec")] - pub data: Vec, + pub data: Vec, } diff --git a/starknet-providers/src/sequencer/models/transaction_request.rs b/starknet-providers/src/sequencer/models/transaction_request.rs index ff294141..35dd5bb6 100644 --- a/starknet-providers/src/sequencer/models/transaction_request.rs +++ b/starknet-providers/src/sequencer/models/transaction_request.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize, Serializer}; use serde_with::serde_as; use starknet_core::{ serde::unsigned_field_element::{UfeHex, UfeHexOption}, - types::FieldElement, + types::Felt, }; use std::sync::Arc; @@ -14,27 +14,27 @@ use super::{ }; /// 2 ^ 128 + 1 -const QUERY_VERSION_ONE: FieldElement = FieldElement::from_mont([ - 18446744073700081633, - 17407, - 18446744073709551584, +const QUERY_VERSION_ONE: Felt = Felt::from_raw([ 576460752142433776, + 18446744073709551584, + 17407, + 18446744073700081633, ]); /// 2 ^ 128 + 2 -const QUERY_VERSION_TWO: FieldElement = FieldElement::from_mont([ - 18446744073700081601, - 17407, - 18446744073709551584, +const QUERY_VERSION_TWO: Felt = Felt::from_raw([ 576460752142433232, + 18446744073709551584, + 17407, + 18446744073700081601, ]); /// 2 ^ 128 + 3 -const QUERY_VERSION_THREE: FieldElement = FieldElement::from_mont([ - 18446744073700081569, - 17407, - 18446744073709551584, +const QUERY_VERSION_THREE: Felt = Felt::from_raw([ 576460752142432688, + 18446744073709551584, + 17407, + 18446744073700081569, ]); #[serde_as] @@ -43,13 +43,13 @@ const QUERY_VERSION_THREE: FieldElement = FieldElement::from_mont([ pub struct AddTransactionResult { pub code: AddTransactionResultCode, #[serde_as(as = "UfeHex")] - pub transaction_hash: FieldElement, + pub transaction_hash: Felt, #[serde(default)] #[serde_as(as = "UfeHexOption")] - pub address: Option, + pub address: Option, #[serde(default)] #[serde_as(as = "UfeHexOption")] - pub class_hash: Option, + pub class_hash: Option, } #[derive(Debug, PartialEq, Eq, Deserialize)] @@ -79,13 +79,13 @@ pub enum DeclareTransaction { pub struct DeclareV1Transaction { pub contract_class: Arc, /// The address of the account contract sending the declaration transaction. - pub sender_address: FieldElement, + pub sender_address: Felt, /// The maximal fee to be paid in Wei for declaring a contract class. - pub max_fee: FieldElement, + pub max_fee: Felt, /// Additional information given by the caller that represents the signature of the transaction. - pub signature: Vec, + pub signature: Vec, /// A sequential integer used to distinguish between transactions and order them. - pub nonce: FieldElement, + pub nonce: Felt, pub is_query: bool, } @@ -96,15 +96,15 @@ pub struct DeclareV2Transaction { /// class. This is required because at the moment, Sierra compilation is not proven, allowing /// the sequencer to run arbitrary code if this is not signed. It's expected that in the future /// this will no longer be required. - pub compiled_class_hash: FieldElement, + pub compiled_class_hash: Felt, /// The address of the account contract sending the declaration transaction. - pub sender_address: FieldElement, + pub sender_address: Felt, /// The maximal fee to be paid in Wei for declaring a contract class. - pub max_fee: FieldElement, + pub max_fee: Felt, /// Additional information given by the caller that represents the signature of the transaction. - pub signature: Vec, + pub signature: Vec, /// A sequential integer used to distinguish between transactions and order them. - pub nonce: FieldElement, + pub nonce: Felt, pub is_query: bool, } @@ -115,19 +115,19 @@ pub struct DeclareV3Transaction { /// class. This is required because at the moment, Sierra compilation is not proven, allowing /// the sequencer to run arbitrary code if this is not signed. It's expected that in the future /// this will no longer be required. - pub compiled_class_hash: FieldElement, + pub compiled_class_hash: Felt, /// The address of the account contract sending the declaration transaction. - pub sender_address: FieldElement, + pub sender_address: Felt, /// Additional information given by the caller that represents the signature of the transaction. - pub signature: Vec, + pub signature: Vec, /// A sequential integer used to distinguish between transactions and order them. - pub nonce: FieldElement, + pub nonce: Felt, pub nonce_data_availability_mode: DataAvailabilityMode, pub fee_data_availability_mode: DataAvailabilityMode, pub resource_bounds: ResourceBoundsMapping, pub tip: u64, - pub paymaster_data: Vec, - pub account_deployment_data: Vec, + pub paymaster_data: Vec, + pub account_deployment_data: Vec, pub is_query: bool, } @@ -140,26 +140,26 @@ pub enum InvokeFunctionTransaction { #[derive(Debug)] pub struct InvokeFunctionV1Transaction { - pub sender_address: FieldElement, - pub calldata: Vec, - pub signature: Vec, - pub max_fee: FieldElement, - pub nonce: FieldElement, + pub sender_address: Felt, + pub calldata: Vec, + pub signature: Vec, + pub max_fee: Felt, + pub nonce: Felt, pub is_query: bool, } #[derive(Debug)] pub struct InvokeFunctionV3Transaction { - pub sender_address: FieldElement, - pub calldata: Vec, - pub signature: Vec, - pub nonce: FieldElement, + pub sender_address: Felt, + pub calldata: Vec, + pub signature: Vec, + pub nonce: Felt, pub nonce_data_availability_mode: DataAvailabilityMode, pub fee_data_availability_mode: DataAvailabilityMode, pub resource_bounds: ResourceBoundsMapping, pub tip: u64, - pub paymaster_data: Vec, - pub account_deployment_data: Vec, + pub paymaster_data: Vec, + pub account_deployment_data: Vec, pub is_query: bool, } @@ -172,32 +172,32 @@ pub enum DeployAccountTransaction { #[derive(Debug)] pub struct DeployAccountV1Transaction { - pub class_hash: FieldElement, - pub contract_address_salt: FieldElement, - pub constructor_calldata: Vec, + pub class_hash: Felt, + pub contract_address_salt: Felt, + pub constructor_calldata: Vec, // The maximal fee to be paid in Wei for executing the transaction. - pub max_fee: FieldElement, + pub max_fee: Felt, // The signature of the transaction. - pub signature: Vec, + pub signature: Vec, // The nonce of the transaction. - pub nonce: FieldElement, + pub nonce: Felt, pub is_query: bool, } #[derive(Debug)] pub struct DeployAccountV3Transaction { - pub class_hash: FieldElement, - pub contract_address_salt: FieldElement, - pub constructor_calldata: Vec, + pub class_hash: Felt, + pub contract_address_salt: Felt, + pub constructor_calldata: Vec, // The signature of the transaction. - pub signature: Vec, + pub signature: Vec, // The nonce of the transaction. - pub nonce: FieldElement, + pub nonce: Felt, pub nonce_data_availability_mode: DataAvailabilityMode, pub fee_data_availability_mode: DataAvailabilityMode, pub resource_bounds: ResourceBoundsMapping, pub tip: u64, - pub paymaster_data: Vec, + pub paymaster_data: Vec, pub is_query: bool, } @@ -210,22 +210,22 @@ impl Serialize for DeclareV1Transaction { #[derive(Serialize)] struct Versioned<'a> { #[serde_as(as = "UfeHex")] - version: FieldElement, + version: Felt, contract_class: &'a CompressedLegacyContractClass, #[serde_as(as = "UfeHex")] - sender_address: &'a FieldElement, + sender_address: &'a Felt, #[serde_as(as = "UfeHex")] - max_fee: &'a FieldElement, - signature: &'a Vec, + max_fee: &'a Felt, + signature: &'a Vec, #[serde_as(as = "UfeHex")] - nonce: &'a FieldElement, + nonce: &'a Felt, } let versioned = Versioned { version: if self.is_query { QUERY_VERSION_ONE } else { - FieldElement::ONE + Felt::ONE }, contract_class: &self.contract_class, sender_address: &self.sender_address, @@ -247,24 +247,24 @@ impl Serialize for DeclareV2Transaction { #[derive(Serialize)] struct Versioned<'a> { #[serde_as(as = "UfeHex")] - version: FieldElement, + version: Felt, contract_class: &'a CompressedSierraClass, #[serde_as(as = "UfeHex")] - compiled_class_hash: &'a FieldElement, + compiled_class_hash: &'a Felt, #[serde_as(as = "UfeHex")] - sender_address: &'a FieldElement, + sender_address: &'a Felt, #[serde_as(as = "UfeHex")] - max_fee: &'a FieldElement, - signature: &'a Vec, + max_fee: &'a Felt, + signature: &'a Vec, #[serde_as(as = "UfeHex")] - nonce: &'a FieldElement, + nonce: &'a Felt, } let versioned = Versioned { version: if self.is_query { QUERY_VERSION_TWO } else { - FieldElement::TWO + Felt::TWO }, contract_class: &self.contract_class, compiled_class_hash: &self.compiled_class_hash, @@ -287,32 +287,32 @@ impl Serialize for DeclareV3Transaction { #[derive(Serialize)] struct Versioned<'a> { #[serde_as(as = "UfeHex")] - version: FieldElement, + version: Felt, contract_class: &'a CompressedSierraClass, #[serde_as(as = "UfeHex")] - compiled_class_hash: &'a FieldElement, + compiled_class_hash: &'a Felt, #[serde_as(as = "UfeHex")] - sender_address: &'a FieldElement, + sender_address: &'a Felt, #[serde_as(as = "Vec")] - signature: &'a Vec, + signature: &'a Vec, #[serde_as(as = "UfeHex")] - nonce: &'a FieldElement, + nonce: &'a Felt, nonce_data_availability_mode: &'a DataAvailabilityMode, fee_data_availability_mode: &'a DataAvailabilityMode, resource_bounds: &'a ResourceBoundsMapping, #[serde(with = "u64_hex")] tip: &'a u64, #[serde_as(as = "Vec")] - paymaster_data: &'a Vec, + paymaster_data: &'a Vec, #[serde_as(as = "Vec")] - account_deployment_data: &'a Vec, + account_deployment_data: &'a Vec, } let versioned = Versioned { version: if self.is_query { QUERY_VERSION_THREE } else { - FieldElement::THREE + Felt::THREE }, contract_class: &self.contract_class, compiled_class_hash: &self.compiled_class_hash, @@ -340,22 +340,22 @@ impl Serialize for InvokeFunctionV1Transaction { #[derive(Serialize)] struct Versioned<'a> { #[serde_as(as = "UfeHex")] - version: FieldElement, + version: Felt, #[serde_as(as = "UfeHex")] - sender_address: &'a FieldElement, - calldata: &'a Vec, - signature: &'a Vec, + sender_address: &'a Felt, + calldata: &'a Vec, + signature: &'a Vec, #[serde_as(as = "UfeHex")] - max_fee: &'a FieldElement, + max_fee: &'a Felt, #[serde_as(as = "UfeHex")] - nonce: &'a FieldElement, + nonce: &'a Felt, } let versioned = Versioned { version: if self.is_query { QUERY_VERSION_ONE } else { - FieldElement::ONE + Felt::ONE }, sender_address: &self.sender_address, calldata: &self.calldata, @@ -377,30 +377,30 @@ impl Serialize for InvokeFunctionV3Transaction { #[derive(Serialize)] struct Versioned<'a> { #[serde_as(as = "UfeHex")] - version: FieldElement, + version: Felt, #[serde_as(as = "UfeHex")] - sender_address: &'a FieldElement, - calldata: &'a Vec, + sender_address: &'a Felt, + calldata: &'a Vec, #[serde_as(as = "Vec")] - signature: &'a Vec, + signature: &'a Vec, #[serde_as(as = "UfeHex")] - nonce: &'a FieldElement, + nonce: &'a Felt, nonce_data_availability_mode: &'a DataAvailabilityMode, fee_data_availability_mode: &'a DataAvailabilityMode, resource_bounds: &'a ResourceBoundsMapping, #[serde(with = "u64_hex")] tip: &'a u64, #[serde_as(as = "Vec")] - paymaster_data: &'a Vec, + paymaster_data: &'a Vec, #[serde_as(as = "Vec")] - account_deployment_data: &'a Vec, + account_deployment_data: &'a Vec, } let versioned = Versioned { version: if self.is_query { QUERY_VERSION_THREE } else { - FieldElement::THREE + Felt::THREE }, sender_address: &self.sender_address, calldata: &self.calldata, @@ -427,24 +427,24 @@ impl Serialize for DeployAccountV1Transaction { #[derive(Serialize)] struct Versioned<'a> { #[serde_as(as = "UfeHex")] - version: FieldElement, + version: Felt, #[serde_as(as = "UfeHex")] - class_hash: &'a FieldElement, + class_hash: &'a Felt, #[serde_as(as = "UfeHex")] - contract_address_salt: &'a FieldElement, - constructor_calldata: &'a Vec, + contract_address_salt: &'a Felt, + constructor_calldata: &'a Vec, #[serde_as(as = "UfeHex")] - max_fee: &'a FieldElement, - signature: &'a Vec, + max_fee: &'a Felt, + signature: &'a Vec, #[serde_as(as = "UfeHex")] - nonce: &'a FieldElement, + nonce: &'a Felt, } let versioned = Versioned { version: if self.is_query { QUERY_VERSION_ONE } else { - FieldElement::ONE + Felt::ONE }, class_hash: &self.class_hash, contract_address_salt: &self.contract_address_salt, @@ -467,31 +467,31 @@ impl Serialize for DeployAccountV3Transaction { #[derive(Serialize)] struct Versioned<'a> { #[serde_as(as = "UfeHex")] - version: FieldElement, + version: Felt, #[serde_as(as = "UfeHex")] - class_hash: &'a FieldElement, + class_hash: &'a Felt, #[serde_as(as = "UfeHex")] - contract_address_salt: &'a FieldElement, + contract_address_salt: &'a Felt, #[serde_as(as = "Vec")] - constructor_calldata: &'a Vec, + constructor_calldata: &'a Vec, #[serde_as(as = "Vec")] - signature: &'a Vec, + signature: &'a Vec, #[serde_as(as = "UfeHex")] - nonce: &'a FieldElement, + nonce: &'a Felt, nonce_data_availability_mode: &'a DataAvailabilityMode, fee_data_availability_mode: &'a DataAvailabilityMode, resource_bounds: &'a ResourceBoundsMapping, #[serde(with = "u64_hex")] tip: &'a u64, #[serde_as(as = "Vec")] - paymaster_data: &'a Vec, + paymaster_data: &'a Vec, } let versioned = Versioned { version: if self.is_query { QUERY_VERSION_THREE } else { - FieldElement::THREE + Felt::THREE }, class_hash: &self.class_hash, contract_address_salt: &self.contract_address_salt, @@ -517,7 +517,7 @@ where buffer[12..].copy_from_slice(&value.0); // Unwrapping is safe here as it's never out of range - let addr_in_felt = FieldElement::from_bytes_be(&buffer).unwrap(); + let addr_in_felt = Felt::from_bytes_be(&buffer); serializer.serialize_str(&addr_in_felt.to_string()) } diff --git a/starknet-providers/src/sequencer/provider.rs b/starknet-providers/src/sequencer/provider.rs index de6b8352..fadb46c9 100644 --- a/starknet-providers/src/sequencer/provider.rs +++ b/starknet-providers/src/sequencer/provider.rs @@ -8,7 +8,7 @@ use starknet_core::types::{ BlockHashAndNumber, BlockId, BroadcastedDeclareTransaction, BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, BroadcastedTransaction, ContractClass, DeclareTransactionResult, DeployAccountTransactionResult, EventFilter, - EventsPage, FeeEstimate, FieldElement, FunctionCall, InvokeTransactionResult, + EventsPage, FeeEstimate, Felt, FunctionCall, InvokeTransactionResult, MaybePendingBlockWithReceipts, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate, MsgFromL1, SimulatedTransaction, SimulationFlag, SimulationFlagForEstimateFee, StarknetError, SyncStatusType, Transaction, @@ -110,10 +110,10 @@ impl Provider for SequencerGatewayProvider { contract_address: A, key: K, block_id: B, - ) -> Result + ) -> Result where - A: AsRef + Send + Sync, - K: AsRef + Send + Sync, + A: AsRef + Send + Sync, + K: AsRef + Send + Sync, B: AsRef + Send + Sync, { // Deprecated since Starknet v0.12.3 @@ -129,14 +129,17 @@ impl Provider for SequencerGatewayProvider { transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { let status = self .get_transaction_status(*transaction_hash.as_ref()) .await?; // `NotReceived` is not a valid status for JSON-RPC. It's an error. - if let Some(TransactionFinalityStatus::NotReceived) = &status.finality_status { + if matches!( + &status.finality_status, + Some(TransactionFinalityStatus::NotReceived) + ) { return Err(ProviderError::StarknetError( StarknetError::TransactionHashNotFound, )); @@ -150,7 +153,7 @@ impl Provider for SequencerGatewayProvider { transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { Ok(self .get_transaction(*transaction_hash.as_ref()) @@ -183,7 +186,7 @@ impl Provider for SequencerGatewayProvider { transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { // Deprecated since Starknet v0.12.3 Err(ProviderError::Other(Box::new( @@ -198,7 +201,7 @@ impl Provider for SequencerGatewayProvider { ) -> Result where B: AsRef + Send + Sync, - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { Ok(self .get_class_by_hash(*class_hash.as_ref(), block_id.as_ref().to_owned().into()) @@ -210,10 +213,10 @@ impl Provider for SequencerGatewayProvider { &self, block_id: B, contract_address: A, - ) -> Result + ) -> Result where B: AsRef + Send + Sync, - A: AsRef + Send + Sync, + A: AsRef + Send + Sync, { // Deprecated since Starknet v0.12.3 Err(ProviderError::Other(Box::new( @@ -228,7 +231,7 @@ impl Provider for SequencerGatewayProvider { ) -> Result where B: AsRef + Send + Sync, - A: AsRef + Send + Sync, + A: AsRef + Send + Sync, { // Deprecated since Starknet v0.12.3 Err(ProviderError::Other(Box::new( @@ -244,7 +247,7 @@ impl Provider for SequencerGatewayProvider { Ok(block.transactions.len() as u64) } - async fn call(&self, request: R, block_id: B) -> Result, ProviderError> + async fn call(&self, request: R, block_id: B) -> Result, ProviderError> where R: AsRef + Send + Sync, B: AsRef + Send + Sync, @@ -300,7 +303,7 @@ impl Provider for SequencerGatewayProvider { }) } - async fn chain_id(&self) -> Result { + async fn chain_id(&self) -> Result { Ok(self.chain_id) } @@ -319,14 +322,10 @@ impl Provider for SequencerGatewayProvider { ))) } - async fn get_nonce( - &self, - block_id: B, - contract_address: A, - ) -> Result + async fn get_nonce(&self, block_id: B, contract_address: A) -> Result where B: AsRef + Send + Sync, - A: AsRef + Send + Sync, + A: AsRef + Send + Sync, { // Deprecated since Starknet v0.12.3 Err(ProviderError::Other(Box::new( @@ -395,7 +394,7 @@ impl Provider for SequencerGatewayProvider { _transaction_hash: H, ) -> Result where - H: AsRef + Send + Sync, + H: AsRef + Send + Sync, { // With JSON-RPC v0.5.0 it's no longer possible to convert feeder traces to JSON-RPC traces. So we simply pretend that it's not supported here. // diff --git a/starknet-providers/tests/jsonrpc.rs b/starknet-providers/tests/jsonrpc.rs index acc7fa3f..dac0910a 100644 --- a/starknet-providers/tests/jsonrpc.rs +++ b/starknet-providers/tests/jsonrpc.rs @@ -2,7 +2,7 @@ use starknet_core::{ types::{ BlockId, BlockTag, BroadcastedInvokeTransaction, BroadcastedInvokeTransactionV1, BroadcastedTransaction, ContractClass, DeclareTransaction, DeployAccountTransaction, - EthAddress, EventFilter, ExecuteInvocation, ExecutionResult, FieldElement, FunctionCall, + EthAddress, EventFilter, ExecuteInvocation, ExecutionResult, Felt, FunctionCall, InvokeTransaction, MaybePendingBlockWithReceipts, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate, MsgFromL1, StarknetError, SyncStatusType, Transaction, TransactionExecutionStatus, TransactionReceipt, @@ -18,7 +18,7 @@ use url::Url; fn create_jsonrpc_client() -> JsonRpcClient { let rpc_url = std::env::var("STARKNET_RPC") - .unwrap_or("https://pathfinder.rpc.sepolia.starknet.rs/rpc/v0_7".into()); + .unwrap_or_else(|_| "https://pathfinder.rpc.sepolia.starknet.rs/rpc/v0_7".into()); JsonRpcClient::new(HttpTransport::new(Url::parse(&rpc_url).unwrap())) } @@ -96,7 +96,7 @@ async fn jsonrpc_get_state_update() { _ => panic!("unexpected data type"), }; - assert!(state_update.new_root > FieldElement::ZERO); + assert!(state_update.new_root > Felt::ZERO); } #[tokio::test] @@ -106,13 +106,11 @@ async fn jsonrpc_get_storage_at() { // Checks L2 ETH balance via storage taking advantage of implementation detail let eth_balance = rpc_client .get_storage_at( - FieldElement::from_hex_be( - "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - ) - .unwrap(), + Felt::from_hex("049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7") + .unwrap(), get_storage_var_address( "ERC20_balances", - &[FieldElement::from_hex_be( + &[Felt::from_hex( "03f47d3911396b6d579fd7848cf576286ab6f96dda977915d6c7b10f3dd2315b", ) .unwrap()], @@ -123,7 +121,7 @@ async fn jsonrpc_get_storage_at() { .await .unwrap(); - assert!(eth_balance > FieldElement::ZERO); + assert!(eth_balance > Felt::ZERO); } // Test case `jsonrpc_get_transaction_status_rejected` was removed as there is no `REJECTED` @@ -135,10 +133,8 @@ async fn jsonrpc_get_transaction_status_succeeded() { let status = rpc_client .get_transaction_status( - FieldElement::from_hex_be( - "03f786ecc4955a2602c91a291328518ef866cb7f3d50e4b16fd42282952623aa", - ) - .unwrap(), + Felt::from_hex("03f786ecc4955a2602c91a291328518ef866cb7f3d50e4b16fd42282952623aa") + .unwrap(), ) .await .unwrap(); @@ -155,10 +151,8 @@ async fn jsonrpc_get_transaction_status_reverted() { let status = rpc_client .get_transaction_status( - FieldElement::from_hex_be( - "02f00c7f28df2197196440747f97baa63d0851e3b0cfc2efedb6a88a7ef78cb1", - ) - .unwrap(), + Felt::from_hex("02f00c7f28df2197196440747f97baa63d0851e3b0cfc2efedb6a88a7ef78cb1") + .unwrap(), ) .await .unwrap(); @@ -178,10 +172,8 @@ async fn jsonrpc_get_transaction_by_hash_invoke_v1() { let tx = rpc_client .get_transaction_by_hash( - FieldElement::from_hex_be( - "03f786ecc4955a2602c91a291328518ef866cb7f3d50e4b16fd42282952623aa", - ) - .unwrap(), + Felt::from_hex("03f786ecc4955a2602c91a291328518ef866cb7f3d50e4b16fd42282952623aa") + .unwrap(), ) .await .unwrap(); @@ -191,7 +183,7 @@ async fn jsonrpc_get_transaction_by_hash_invoke_v1() { _ => panic!("unexpected tx response type"), }; - assert!(tx.sender_address > FieldElement::ZERO); + assert!(tx.sender_address > Felt::ZERO); } #[tokio::test] @@ -200,10 +192,8 @@ async fn jsonrpc_get_transaction_by_hash_l1_handler() { let tx = rpc_client .get_transaction_by_hash( - FieldElement::from_hex_be( - "0785c2ada3f53fbc66078d47715c27718f92e6e48b96372b36e5197de69b82b5", - ) - .unwrap(), + Felt::from_hex("0785c2ada3f53fbc66078d47715c27718f92e6e48b96372b36e5197de69b82b5") + .unwrap(), ) .await .unwrap(); @@ -213,7 +203,7 @@ async fn jsonrpc_get_transaction_by_hash_l1_handler() { _ => panic!("unexpected tx response type"), }; - assert!(tx.entry_point_selector > FieldElement::ZERO); + assert!(tx.entry_point_selector > Felt::ZERO); } #[tokio::test] @@ -222,10 +212,8 @@ async fn jsonrpc_get_transaction_by_hash_declare_v0() { let tx = rpc_client .get_transaction_by_hash( - FieldElement::from_hex_be( - "030a541df2547ed9f94602c35daf61ce3a8e179ec75d26cbe34e0ec61f823695", - ) - .unwrap(), + Felt::from_hex("030a541df2547ed9f94602c35daf61ce3a8e179ec75d26cbe34e0ec61f823695") + .unwrap(), ) .await .unwrap(); @@ -235,7 +223,7 @@ async fn jsonrpc_get_transaction_by_hash_declare_v0() { _ => panic!("unexpected tx response type"), }; - assert!(tx.sender_address > FieldElement::ZERO); + assert!(tx.sender_address > Felt::ZERO); } #[tokio::test] @@ -244,10 +232,8 @@ async fn jsonrpc_get_transaction_by_hash_declare_v1() { let tx = rpc_client .get_transaction_by_hash( - FieldElement::from_hex_be( - "01936a09e5aaee208fc0f7cc826e126d421c3ac9aca2c789605e1e919e399185", - ) - .unwrap(), + Felt::from_hex("01936a09e5aaee208fc0f7cc826e126d421c3ac9aca2c789605e1e919e399185") + .unwrap(), ) .await .unwrap(); @@ -257,7 +243,7 @@ async fn jsonrpc_get_transaction_by_hash_declare_v1() { _ => panic!("unexpected tx response type"), }; - assert!(tx.sender_address > FieldElement::ZERO); + assert!(tx.sender_address > Felt::ZERO); } #[tokio::test] @@ -266,10 +252,8 @@ async fn jsonrpc_get_transaction_by_hash_declare_v2() { let tx = rpc_client .get_transaction_by_hash( - FieldElement::from_hex_be( - "004cacc2bbdd5ec77b20e908f311ab27d6495b69761e929bb24ba02632716944", - ) - .unwrap(), + Felt::from_hex("004cacc2bbdd5ec77b20e908f311ab27d6495b69761e929bb24ba02632716944") + .unwrap(), ) .await .unwrap(); @@ -279,7 +263,7 @@ async fn jsonrpc_get_transaction_by_hash_declare_v2() { _ => panic!("unexpected tx response type"), }; - assert!(tx.sender_address > FieldElement::ZERO); + assert!(tx.sender_address > Felt::ZERO); } #[tokio::test] @@ -288,10 +272,8 @@ async fn jsonrpc_get_transaction_by_hash_declare_v3() { let tx = rpc_client .get_transaction_by_hash( - FieldElement::from_hex_be( - "054270d103c875a613e013d1fd555edcff2085feca9d7b4532243a8257fd5cf3", - ) - .unwrap(), + Felt::from_hex("054270d103c875a613e013d1fd555edcff2085feca9d7b4532243a8257fd5cf3") + .unwrap(), ) .await .unwrap(); @@ -301,7 +283,7 @@ async fn jsonrpc_get_transaction_by_hash_declare_v3() { _ => panic!("unexpected tx response type"), }; - assert!(tx.sender_address > FieldElement::ZERO); + assert!(tx.sender_address > Felt::ZERO); } // Test case `jsonrpc_get_transaction_by_hash_deploy` was removed as there is no `DEPLOY` @@ -313,10 +295,8 @@ async fn jsonrpc_get_transaction_by_hash_deploy_account_v1() { let tx = rpc_client .get_transaction_by_hash( - FieldElement::from_hex_be( - "024ed6b82e2f6d3a811ec180a25c1ccd0bdc7bdba8ebd709de2ed697a1e82193", - ) - .unwrap(), + Felt::from_hex("024ed6b82e2f6d3a811ec180a25c1ccd0bdc7bdba8ebd709de2ed697a1e82193") + .unwrap(), ) .await .unwrap(); @@ -326,7 +306,7 @@ async fn jsonrpc_get_transaction_by_hash_deploy_account_v1() { _ => panic!("unexpected tx response type"), }; - assert!(tx.class_hash > FieldElement::ZERO); + assert!(tx.class_hash > Felt::ZERO); } #[tokio::test] @@ -335,10 +315,8 @@ async fn jsonrpc_get_transaction_by_hash_deploy_account_v3() { let tx = rpc_client .get_transaction_by_hash( - FieldElement::from_hex_be( - "011c67fb3a9a623b3190c9ac41ebf7f5dd421f2583344c498a30a7280c660f01", - ) - .unwrap(), + Felt::from_hex("011c67fb3a9a623b3190c9ac41ebf7f5dd421f2583344c498a30a7280c660f01") + .unwrap(), ) .await .unwrap(); @@ -348,7 +326,7 @@ async fn jsonrpc_get_transaction_by_hash_deploy_account_v3() { _ => panic!("unexpected tx response type"), }; - assert!(tx.class_hash > FieldElement::ZERO); + assert!(tx.class_hash > Felt::ZERO); } #[tokio::test] @@ -365,7 +343,7 @@ async fn jsonrpc_get_transaction_by_block_id_and_index() { _ => panic!("unexpected tx response type"), }; - assert!(tx.sender_address > FieldElement::ZERO); + assert!(tx.sender_address > Felt::ZERO); } #[tokio::test] @@ -373,7 +351,7 @@ async fn jsonrpc_get_transaction_by_hash_non_existent_tx() { let rpc_client = create_jsonrpc_client(); let err = rpc_client - .get_transaction_by_hash(FieldElement::from_hex_be("1234").unwrap()) + .get_transaction_by_hash(Felt::from_hex("1234").unwrap()) .await .unwrap_err(); @@ -391,10 +369,8 @@ async fn jsonrpc_get_transaction_receipt_invoke() { let receipt = rpc_client .get_transaction_receipt( - FieldElement::from_hex_be( - "03f786ecc4955a2602c91a291328518ef866cb7f3d50e4b16fd42282952623aa", - ) - .unwrap(), + Felt::from_hex("03f786ecc4955a2602c91a291328518ef866cb7f3d50e4b16fd42282952623aa") + .unwrap(), ) .await .unwrap(); @@ -418,10 +394,8 @@ async fn jsonrpc_get_transaction_receipt_invoke_reverted() { let receipt = rpc_client .get_transaction_receipt( - FieldElement::from_hex_be( - "02f00c7f28df2197196440747f97baa63d0851e3b0cfc2efedb6a88a7ef78cb1", - ) - .unwrap(), + Felt::from_hex("02f00c7f28df2197196440747f97baa63d0851e3b0cfc2efedb6a88a7ef78cb1") + .unwrap(), ) .await .unwrap(); @@ -443,10 +417,8 @@ async fn jsonrpc_get_transaction_receipt_invoke_reverted() { async fn jsonrpc_get_transaction_receipt_l1_handler() { let rpc_client = create_jsonrpc_client(); - let tx_hash = FieldElement::from_hex_be( - "0785c2ada3f53fbc66078d47715c27718f92e6e48b96372b36e5197de69b82b5", - ) - .unwrap(); + let tx_hash = + Felt::from_hex("0785c2ada3f53fbc66078d47715c27718f92e6e48b96372b36e5197de69b82b5").unwrap(); let tx = rpc_client.get_transaction_by_hash(tx_hash).await.unwrap(); let receipt = rpc_client.get_transaction_receipt(tx_hash).await.unwrap(); @@ -477,10 +449,8 @@ async fn jsonrpc_get_transaction_receipt_declare() { let receipt = rpc_client .get_transaction_receipt( - FieldElement::from_hex_be( - "01936a09e5aaee208fc0f7cc826e126d421c3ac9aca2c789605e1e919e399185", - ) - .unwrap(), + Felt::from_hex("01936a09e5aaee208fc0f7cc826e126d421c3ac9aca2c789605e1e919e399185") + .unwrap(), ) .await .unwrap(); @@ -507,10 +477,8 @@ async fn jsonrpc_get_transaction_receipt_deploy_account() { let receipt = rpc_client .get_transaction_receipt( - FieldElement::from_hex_be( - "024ed6b82e2f6d3a811ec180a25c1ccd0bdc7bdba8ebd709de2ed697a1e82193", - ) - .unwrap(), + Felt::from_hex("024ed6b82e2f6d3a811ec180a25c1ccd0bdc7bdba8ebd709de2ed697a1e82193") + .unwrap(), ) .await .unwrap(); @@ -535,10 +503,8 @@ async fn jsonrpc_get_class_cairo_0() { let class = rpc_client .get_class( BlockId::Tag(BlockTag::Latest), - FieldElement::from_hex_be( - "07b3e05f48f0c69e4a65ce5e076a66271a527aff2c34ce1083ec6e1526997a69", - ) - .unwrap(), + Felt::from_hex("07b3e05f48f0c69e4a65ce5e076a66271a527aff2c34ce1083ec6e1526997a69") + .unwrap(), ) .await .unwrap(); @@ -558,10 +524,8 @@ async fn jsonrpc_get_class_cairo_1() { let class = rpc_client .get_class( BlockId::Tag(BlockTag::Latest), - FieldElement::from_hex_be( - "01a736d6ed154502257f02b1ccdf4d9d1089f80811cd6acad48e6b6a9d1f2003", - ) - .unwrap(), + Felt::from_hex("01a736d6ed154502257f02b1ccdf4d9d1089f80811cd6acad48e6b6a9d1f2003") + .unwrap(), ) .await .unwrap(); @@ -581,20 +545,15 @@ async fn jsonrpc_get_class_hash_at() { let class_hash = rpc_client .get_class_hash_at( BlockId::Tag(BlockTag::Latest), - FieldElement::from_hex_be( - "041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf", - ) - .unwrap(), + Felt::from_hex("041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf") + .unwrap(), ) .await .unwrap(); assert_eq!( class_hash, - FieldElement::from_hex_be( - "07b3e05f48f0c69e4a65ce5e076a66271a527aff2c34ce1083ec6e1526997a69" - ) - .unwrap() + Felt::from_hex("07b3e05f48f0c69e4a65ce5e076a66271a527aff2c34ce1083ec6e1526997a69").unwrap() ); } @@ -605,10 +564,8 @@ async fn jsonrpc_get_class_at() { let class = rpc_client .get_class_at( BlockId::Tag(BlockTag::Latest), - FieldElement::from_hex_be( - "041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf", - ) - .unwrap(), + Felt::from_hex("041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf") + .unwrap(), ) .await .unwrap(); @@ -641,12 +598,12 @@ async fn jsonrpc_call() { let eth_balance = rpc_client .call( &FunctionCall { - contract_address: FieldElement::from_hex_be( + contract_address: Felt::from_hex( "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", ) .unwrap(), entry_point_selector: get_selector_from_name("balanceOf").unwrap(), - calldata: vec![FieldElement::from_hex_be( + calldata: vec![Felt::from_hex( "03f47d3911396b6d579fd7848cf576286ab6f96dda977915d6c7b10f3dd2315b", ) .unwrap()], @@ -656,7 +613,7 @@ async fn jsonrpc_call() { .await .unwrap(); - assert!(eth_balance[0] > FieldElement::ZERO); + assert!(eth_balance[0] > Felt::ZERO); } #[tokio::test] @@ -667,36 +624,36 @@ async fn jsonrpc_estimate_fee() { .estimate_fee_single( BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1( BroadcastedInvokeTransactionV1 { - max_fee: FieldElement::ZERO, + max_fee: Felt::ZERO, signature: vec![ - FieldElement::from_hex_be( + Felt::from_hex( "0024bd9efc809227bbcdfbd5a38b9255562184f944336c662037865dddda7a98", ) .unwrap(), - FieldElement::from_hex_be( + Felt::from_hex( "0647f552129f367c1053caeb722c3e1d5719032e229c08dbfde988bd87c9cc3e", ) .unwrap(), ], - nonce: FieldElement::ONE, - sender_address: FieldElement::from_hex_be( + nonce: Felt::ONE, + sender_address: Felt::from_hex( "047e5089068f45ed6f7e1396157cd2346dfecbf1c77f396c03d45db3b164f5a0", ) .unwrap(), calldata: vec![ - FieldElement::from_hex_be("1").unwrap(), - FieldElement::from_hex_be( + Felt::from_hex("1").unwrap(), + Felt::from_hex( "049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", ) .unwrap(), - FieldElement::from_hex_be( + Felt::from_hex( "0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", ) .unwrap(), - FieldElement::from_hex_be("3").unwrap(), - FieldElement::from_hex_be("1234").unwrap(), - FieldElement::from_hex_be("64").unwrap(), - FieldElement::from_hex_be("0").unwrap(), + Felt::from_hex("3").unwrap(), + Felt::from_hex("1234").unwrap(), + Felt::from_hex("64").unwrap(), + Felt::from_hex("0").unwrap(), ], is_query: true, }, @@ -707,9 +664,9 @@ async fn jsonrpc_estimate_fee() { .await .unwrap(); - assert!(estimate.gas_consumed > FieldElement::ZERO); - assert!(estimate.gas_price > FieldElement::ZERO); - assert!(estimate.overall_fee > FieldElement::ZERO); + assert!(estimate.gas_consumed > Felt::ZERO); + assert!(estimate.gas_price > Felt::ZERO); + assert!(estimate.overall_fee > Felt::ZERO); } #[tokio::test] @@ -721,24 +678,24 @@ async fn jsonrpc_estimate_message_fee() { MsgFromL1 { from_address: EthAddress::from_hex("0x8453FC6Cd1bCfE8D4dFC069C400B433054d47bDc") .unwrap(), - to_address: FieldElement::from_hex_be( + to_address: Felt::from_hex( "04c5772d1914fe6ce891b64eb35bf3522aeae1315647314aac58b01137607f3f", ) .unwrap(), - entry_point_selector: FieldElement::from_hex_be( + entry_point_selector: Felt::from_hex( "02d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5", ) .unwrap(), - payload: vec![FieldElement::ONE, FieldElement::ONE, FieldElement::ONE], + payload: vec![Felt::ONE, Felt::ONE, Felt::ONE], }, BlockId::Tag(BlockTag::Latest), ) .await .unwrap(); - assert!(estimate.gas_consumed > FieldElement::ZERO); - assert!(estimate.gas_price > FieldElement::ZERO); - assert!(estimate.overall_fee > FieldElement::ZERO); + assert!(estimate.gas_consumed > Felt::ZERO); + assert!(estimate.gas_price > Felt::ZERO); + assert!(estimate.overall_fee > Felt::ZERO); } #[tokio::test] @@ -755,7 +712,7 @@ async fn jsonrpc_block_hash_and_number() { let id = rpc_client.block_hash_and_number().await.unwrap(); - assert!(id.block_hash > FieldElement::ZERO); + assert!(id.block_hash > Felt::ZERO); assert!(id.block_number > 0); } @@ -764,7 +721,7 @@ async fn jsonrpc_chain_id() { let rpc_client = create_jsonrpc_client(); let chain_id = rpc_client.chain_id().await.unwrap(); - assert!(chain_id > FieldElement::ZERO); + assert!(chain_id > Felt::ZERO); } #[tokio::test] @@ -805,15 +762,13 @@ async fn jsonrpc_get_nonce() { let nonce = rpc_client .get_nonce( BlockId::Tag(BlockTag::Latest), - FieldElement::from_hex_be( - "047e5089068f45ed6f7e1396157cd2346dfecbf1c77f396c03d45db3b164f5a0", - ) - .unwrap(), + Felt::from_hex("047e5089068f45ed6f7e1396157cd2346dfecbf1c77f396c03d45db3b164f5a0") + .unwrap(), ) .await .unwrap(); - assert_eq!(nonce, FieldElement::ONE); + assert_eq!(nonce, Felt::ONE); } #[tokio::test] @@ -822,10 +777,8 @@ async fn jsonrpc_trace_invoke() { let trace = rpc_client .trace_transaction( - FieldElement::from_hex_be( - "03f786ecc4955a2602c91a291328518ef866cb7f3d50e4b16fd42282952623aa", - ) - .unwrap(), + Felt::from_hex("03f786ecc4955a2602c91a291328518ef866cb7f3d50e4b16fd42282952623aa") + .unwrap(), ) .await .unwrap(); @@ -847,10 +800,8 @@ async fn jsonrpc_trace_invoke_reverted() { let trace = rpc_client .trace_transaction( - FieldElement::from_hex_be( - "02f00c7f28df2197196440747f97baa63d0851e3b0cfc2efedb6a88a7ef78cb1", - ) - .unwrap(), + Felt::from_hex("02f00c7f28df2197196440747f97baa63d0851e3b0cfc2efedb6a88a7ef78cb1") + .unwrap(), ) .await .unwrap(); @@ -872,10 +823,8 @@ async fn jsonrpc_trace_l1_handler() { let trace = rpc_client .trace_transaction( - FieldElement::from_hex_be( - "0785c2ada3f53fbc66078d47715c27718f92e6e48b96372b36e5197de69b82b5", - ) - .unwrap(), + Felt::from_hex("0785c2ada3f53fbc66078d47715c27718f92e6e48b96372b36e5197de69b82b5") + .unwrap(), ) .await .unwrap(); @@ -892,10 +841,8 @@ async fn jsonrpc_trace_declare() { let trace = rpc_client .trace_transaction( - FieldElement::from_hex_be( - "01936a09e5aaee208fc0f7cc826e126d421c3ac9aca2c789605e1e919e399185", - ) - .unwrap(), + Felt::from_hex("01936a09e5aaee208fc0f7cc826e126d421c3ac9aca2c789605e1e919e399185") + .unwrap(), ) .await .unwrap(); @@ -914,10 +861,8 @@ async fn jsonrpc_trace_deploy_account() { let trace = rpc_client .trace_transaction( - FieldElement::from_hex_be( - "024ed6b82e2f6d3a811ec180a25c1ccd0bdc7bdba8ebd709de2ed697a1e82193", - ) - .unwrap(), + Felt::from_hex("024ed6b82e2f6d3a811ec180a25c1ccd0bdc7bdba8ebd709de2ed697a1e82193") + .unwrap(), ) .await .unwrap(); diff --git a/starknet-signers/Cargo.toml b/starknet-signers/Cargo.toml index dc64c7c0..f608b25f 100644 --- a/starknet-signers/Cargo.toml +++ b/starknet-signers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starknet-signers" -version = "0.8.0" +version = "0.9.0" authors = ["Jonathan LEI "] license = "MIT OR Apache-2.0" edition = "2021" @@ -13,16 +13,32 @@ Starknet signer implementations keywords = ["ethereum", "starknet", "web3"] [dependencies] -starknet-core = { version = "0.10.0", path = "../starknet-core" } -starknet-crypto = { version = "0.6.2", path = "../starknet-crypto" } +starknet-core = { version = "0.11.1", path = "../starknet-core" } +starknet-crypto = { version = "0.7.1", path = "../starknet-crypto" } async-trait = "0.1.68" auto_impl = "1.0.1" thiserror = "1.0.40" crypto-bigint = { version = "0.5.1", default-features = false } rand = { version = "0.8.5", features = ["std_rng"] } +coins-bip32 = { version = "0.11.1", optional = true } +semver = { version = "1.0.23", optional = true } + +# Using a fork until https://github.com/summa-tx/coins/issues/137 is fixed +coins-ledger = { git = "https://github.com/xJonathanLEI/coins", rev = "0e3be5db0b18b683433de6b666556b99c726e785", default-features = false, optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] eth-keystore = { version = "0.5.0", default-features = false } +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { version = "0.2.9", features = ["js"] } + [target.'cfg(target_arch = "wasm32")'.dev-dependencies] wasm-bindgen-test = "0.3.34" + +[features] +default = [] + +ledger = ["coins-bip32", "coins-ledger", "semver"] + +[lints] +workspace = true diff --git a/starknet-signers/src/key_pair.rs b/starknet-signers/src/key_pair.rs index 23ad1276..65047f20 100644 --- a/starknet-signers/src/key_pair.rs +++ b/starknet-signers/src/key_pair.rs @@ -2,18 +2,18 @@ use crypto_bigint::{Encoding, NonZero, U256}; use rand::{rngs::StdRng, Rng, SeedableRng}; use starknet_core::{ crypto::{ecdsa_sign, ecdsa_verify, EcdsaSignError, EcdsaVerifyError, Signature}, - types::FieldElement, + types::Felt, }; use starknet_crypto::get_public_key; #[derive(Debug, Clone)] pub struct SigningKey { - secret_scalar: FieldElement, + secret_scalar: Felt, } #[derive(Debug, Clone)] pub struct VerifyingKey { - scalar: FieldElement, + scalar: Felt, } #[cfg(not(target_arch = "wasm32"))] @@ -42,12 +42,12 @@ impl SigningKey { let secret_scalar = random_u256.rem(&PRIME); // It's safe to unwrap here as we're 100% sure it's not out of range - let secret_scalar = FieldElement::from_byte_slice_be(&secret_scalar.to_be_bytes()).unwrap(); + let secret_scalar = Felt::from_bytes_be_slice(&secret_scalar.to_be_bytes()); Self { secret_scalar } } - pub fn from_secret_scalar(secret_scalar: FieldElement) -> Self { + pub const fn from_secret_scalar(secret_scalar: Felt) -> Self { Self { secret_scalar } } @@ -58,8 +58,7 @@ impl SigningKey { P: AsRef, { let key = eth_keystore::decrypt_key(path, password).map_err(KeystoreError::Inner)?; - let secret_scalar = - FieldElement::from_byte_slice_be(&key).map_err(|_| KeystoreError::InvalidScalar)?; + let secret_scalar = Felt::from_bytes_be_slice(&key); Ok(Self::from_secret_scalar(secret_scalar)) } @@ -93,7 +92,7 @@ impl SigningKey { Ok(()) } - pub fn secret_scalar(&self) -> FieldElement { + pub const fn secret_scalar(&self) -> Felt { self.secret_scalar } @@ -101,25 +100,21 @@ impl SigningKey { VerifyingKey::from_scalar(get_public_key(&self.secret_scalar)) } - pub fn sign(&self, hash: &FieldElement) -> Result { + pub fn sign(&self, hash: &Felt) -> Result { ecdsa_sign(&self.secret_scalar, hash).map(|sig| sig.into()) } } impl VerifyingKey { - pub fn from_scalar(scalar: FieldElement) -> Self { + pub const fn from_scalar(scalar: Felt) -> Self { Self { scalar } } - pub fn scalar(&self) -> FieldElement { + pub const fn scalar(&self) -> Felt { self.scalar } - pub fn verify( - &self, - hash: &FieldElement, - signature: &Signature, - ) -> Result { + pub fn verify(&self, hash: &Felt, signature: &Signature) -> Result { ecdsa_verify(&self.scalar, hash, signature) } } @@ -132,10 +127,9 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_get_secret_scalar() { // Generated with `cairo-lang` - let private_key = FieldElement::from_hex_be( - "0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79", - ) - .unwrap(); + let private_key = + Felt::from_hex("0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79") + .unwrap(); let signing_key = SigningKey::from_secret_scalar(private_key); @@ -146,14 +140,12 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_get_verifying_key() { // Generated with `cairo-lang` - let private_key = FieldElement::from_hex_be( - "0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79", - ) - .unwrap(); - let expected_public_key = FieldElement::from_hex_be( - "02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159", - ) - .unwrap(); + let private_key = + Felt::from_hex("0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79") + .unwrap(); + let expected_public_key = + Felt::from_hex("02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159") + .unwrap(); let signing_key = SigningKey::from_secret_scalar(private_key); let verifying_key = signing_key.verifying_key(); @@ -165,22 +157,18 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_sign() { // Generated with `cairo-lang` - let private_key = FieldElement::from_hex_be( - "0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79", - ) - .unwrap(); - let hash = FieldElement::from_hex_be( - "06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76", - ) - .unwrap(); - let expected_r = FieldElement::from_hex_be( - "061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f", - ) - .unwrap(); - let expected_s = FieldElement::from_hex_be( - "04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a", - ) - .unwrap(); + let private_key = + Felt::from_hex("0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79") + .unwrap(); + let hash = + Felt::from_hex("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76") + .unwrap(); + let expected_r = + Felt::from_hex("061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f") + .unwrap(); + let expected_s = + Felt::from_hex("04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a") + .unwrap(); let signing_key = SigningKey::from_secret_scalar(private_key); let signature = signing_key.sign(&hash).unwrap(); @@ -192,14 +180,12 @@ mod tests { #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_hash_out_of_range() { - let private_key = FieldElement::from_hex_be( - "0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79", - ) - .unwrap(); - let hash = FieldElement::from_hex_be( - "0800000000000000000000000000000000000000000000000000000000000000", - ) - .unwrap(); + let private_key = + Felt::from_hex("0139fe4d6f02e666e86a6f58e65060f115cd3c185bd9e98bd829636931458f79") + .unwrap(); + let hash = + Felt::from_hex("0800000000000000000000000000000000000000000000000000000000000000") + .unwrap(); let signing_key = SigningKey::from_secret_scalar(private_key); @@ -213,22 +199,16 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_verify_valid_signature() { // Generated with `cairo-lang` - let public_key = FieldElement::from_hex_be( - "02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159", - ) - .unwrap(); - let hash = FieldElement::from_hex_be( - "06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76", - ) - .unwrap(); - let r = FieldElement::from_hex_be( - "061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f", - ) - .unwrap(); - let s = FieldElement::from_hex_be( - "04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a", - ) - .unwrap(); + let public_key = + Felt::from_hex("02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159") + .unwrap(); + let hash = + Felt::from_hex("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76") + .unwrap(); + let r = Felt::from_hex("061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f") + .unwrap(); + let s = Felt::from_hex("04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9a") + .unwrap(); let verifying_key = VerifyingKey::from_scalar(public_key); @@ -239,22 +219,16 @@ mod tests { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_verify_invalid_signature() { // Generated with `cairo-lang` - let public_key = FieldElement::from_hex_be( - "02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159", - ) - .unwrap(); - let hash = FieldElement::from_hex_be( - "06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76", - ) - .unwrap(); - let r = FieldElement::from_hex_be( - "061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f", - ) - .unwrap(); - let s = FieldElement::from_hex_be( - "04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9b", - ) - .unwrap(); + let public_key = + Felt::from_hex("02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159") + .unwrap(); + let hash = + Felt::from_hex("06fea80189363a786037ed3e7ba546dad0ef7de49fccae0e31eb658b7dd4ea76") + .unwrap(); + let r = Felt::from_hex("061ec782f76a66f6984efc3a1b6d152a124c701c00abdd2bf76641b4135c770f") + .unwrap(); + let s = Felt::from_hex("04e44e759cea02c23568bb4d8a09929bbca8768ab68270d50c18d214166ccd9b") + .unwrap(); let verifying_key = VerifyingKey::from_scalar(public_key); diff --git a/starknet-signers/src/ledger.rs b/starknet-signers/src/ledger.rs new file mode 100644 index 00000000..e86ae90d --- /dev/null +++ b/starknet-signers/src/ledger.rs @@ -0,0 +1,348 @@ +use async_trait::async_trait; +use coins_ledger::{ + common::{APDUData, APDUResponseCodes}, + transports::LedgerAsync, + APDUAnswer, APDUCommand, Ledger, +}; +use crypto_bigint::{ArrayEncoding, U256}; +use semver::Version; +use starknet_core::{crypto::Signature, types::Felt}; + +use crate::{Signer, VerifyingKey}; + +pub use coins_bip32::path::DerivationPath; + +/// The Ledger application identifier for app-starknet. +const CLA_STARKNET: u8 = 0x5a; + +/// BIP-32 encoding of `2645'` +const EIP_2645_PURPOSE: u32 = 0x80000a55; + +const EIP_2645_PATH_LENGTH: usize = 6; + +const VERSION_SIZE: usize = 3; +const PUBLIC_KEY_SIZE: usize = 65; +const SIGNATURE_SIZE: usize = 65; + +/// Ledger app wrapper that implements the [`Signer`] trait. +#[derive(Debug)] +pub struct LedgerSigner { + app: LedgerStarknetApp, + derivation_path: DerivationPath, +} + +/// A handle for communicating with the Ledger Starknet app. +#[derive(Debug)] +pub struct LedgerStarknetApp { + transport: Ledger, +} + +#[derive(Debug, thiserror::Error)] +pub enum LedgerError { + #[error("derivation path is empty, not prefixed with m/2645', or is not 6-level long")] + InvalidDerivationPath, + #[error(transparent)] + TransportError(coins_ledger::LedgerError), + #[error("unknown response code from Ledger: {0}")] + UnknownResponseCode(u16), + #[error("failed Ledger request: {0}")] + UnsuccessfulRequest(APDUResponseCodes), + #[error("unexpected response length - expected: {expected}; actual: {actual}")] + UnexpectedResponseLength { expected: usize, actual: usize }, +} + +/// The `GetPubKey` Ledger command. +struct GetVersion; + +/// The `GetPubKey` Ledger command. +struct GetPubKeyCommand { + display: bool, + path: DerivationPath, +} + +/// Part 1 of the `SignHash` command for setting path. +struct SignHashCommand1 { + path: DerivationPath, +} + +/// Part 2 of the `SignHash` command for setting hash. +struct SignHashCommand2 { + hash: [u8; 32], +} + +impl LedgerSigner { + /// Initializes the Starknet Ledger app. Attempts to find and connect to a Ledger device. The + /// device must be unlocked and have the Starknet app open. + /// + /// The `derivation_path` passed in _must_ follow EIP-2645, i.e. having `2645'` as its "purpose" + /// level as per BIP-44, as the Ledger app does not allow other paths to be used. + /// + /// The path _must_ also be 6-level in length. An example path for Starknet would be: + /// + /// `m/2645'/1195502025'/1470455285'/0'/0'/0` + /// + /// where: + /// + /// - `2645'` is the EIP-2645 prefix + /// - `1195502025'`, decimal for `0x4741e9c9`, is the 31 lowest bits for `sha256(starknet)` + /// - `1470455285'`, decimal for `0x57a55df5`, is the 31 lowest bits for `sha256(starkli)` + /// + /// Currently, the Ledger app only enforces the length and the first level of the path. + pub async fn new(derivation_path: DerivationPath) -> Result { + if !matches!(derivation_path.iter().next(), Some(&EIP_2645_PURPOSE)) + || derivation_path.len() != EIP_2645_PATH_LENGTH + { + return Err(LedgerError::InvalidDerivationPath); + } + + Ok(Self { + app: LedgerStarknetApp::new().await?, + derivation_path, + }) + } +} + +#[async_trait] +impl Signer for LedgerSigner { + type GetPublicKeyError = LedgerError; + type SignError = LedgerError; + + async fn get_public_key(&self) -> Result { + self.app + .get_public_key(self.derivation_path.clone(), false) + .await + } + + async fn sign_hash(&self, hash: &Felt) -> Result { + self.app.sign_hash(self.derivation_path.clone(), hash).await + } + + fn is_interactive(&self) -> bool { + true + } +} + +impl LedgerStarknetApp { + /// Initializes the Starknet Ledger app. Attempts to find and connect to a Ledger device. The + /// device must be unlocked and have the Starknet app open. + pub async fn new() -> Result { + let transport = Ledger::init().await?; + + Ok(Self { transport }) + } + + /// Gets the Ledger app version. + pub async fn get_version(&self) -> Result { + let response = self.transport.exchange(&GetVersion.into()).await?; + + let data = get_apdu_data(&response)?; + if data.len() != VERSION_SIZE { + return Err(LedgerError::UnexpectedResponseLength { + expected: VERSION_SIZE, + actual: data.len(), + }); + } + + Ok(Version::new(data[0] as u64, data[1] as u64, data[2] as u64)) + } + + /// Gets a public key from the app for a particular derivation path, with optional on-device + /// confirmation for extra security. + /// + /// The derivation path _must_ follow EIP-2645, i.e. having `2645'` as its "purpose" level as + /// per BIP-44, as the Ledger app does not allow other paths to be used. + /// + /// The path _must_ also be 6-level in length. An example path for Starknet would be: + /// + /// `m/2645'/1195502025'/1470455285'/0'/0'/0` + /// + /// where: + /// + /// - `2645'` is the EIP-2645 prefix + /// - `1195502025'`, decimal for `0x4741e9c9`, is the 31 lowest bits for `sha256(starknet)` + /// - `1470455285'`, decimal for `0x57a55df5`, is the 31 lowest bits for `sha256(starkli)` + /// + /// Currently, the Ledger app only enforces the length and the first level of the path. + pub async fn get_public_key( + &self, + derivation_path: DerivationPath, + display: bool, + ) -> Result { + let response = self + .transport + .exchange( + &GetPubKeyCommand { + display, + path: derivation_path, + } + .into(), + ) + .await?; + + let data = get_apdu_data(&response)?; + if data.len() != PUBLIC_KEY_SIZE { + return Err(LedgerError::UnexpectedResponseLength { + expected: PUBLIC_KEY_SIZE, + actual: data.len(), + }); + } + + // Unwrapping here is safe as length is fixed + let pubkey_x = Felt::from_bytes_be(&data[1..33].try_into().unwrap()); + + Ok(VerifyingKey::from_scalar(pubkey_x)) + } + + /// Requests a signature for a **raw hash** with a certain derivation path. Currently the Ledger + /// app only supports blind signing raw hashes. + /// + /// The derivation path _must_ follow EIP-2645, i.e. having `2645'` as its "purpose" level as + /// per BIP-44, as the Ledger app does not allow other paths to be used. + /// + /// The path _must_ also be 6-level in length. An example path for Starknet would be: + /// + /// `m/2645'/1195502025'/1470455285'/0'/0'/0` + /// + /// where: + /// + /// - `2645'` is the EIP-2645 prefix + /// - `1195502025'`, decimal for `0x4741e9c9`, is the 31 lowest bits for `sha256(starknet)` + /// - `1470455285'`, decimal for `0x57a55df5`, is the 31 lowest bits for `sha256(starkli)` + /// + /// Currently, the Ledger app only enforces the length and the first level of the path. + pub async fn sign_hash( + &self, + derivation_path: DerivationPath, + hash: &Felt, + ) -> Result { + get_apdu_data( + &self + .transport + .exchange( + &SignHashCommand1 { + path: derivation_path, + } + .into(), + ) + .await?, + )?; + + let response = self + .transport + .exchange( + &SignHashCommand2 { + hash: hash.to_bytes_be(), + } + .into(), + ) + .await?; + + let data = get_apdu_data(&response)?; + + if data.len() != SIGNATURE_SIZE + 1 || data[0] != SIGNATURE_SIZE as u8 { + return Err(LedgerError::UnexpectedResponseLength { + expected: SIGNATURE_SIZE, + actual: data.len(), + }); + } + + // Unwrapping here is safe as length is fixed + let r = Felt::from_bytes_be(&data[1..33].try_into().unwrap()); + let s = Felt::from_bytes_be(&data[33..65].try_into().unwrap()); + + let signature = Signature { r, s }; + + Ok(signature) + } +} + +impl From for LedgerError { + fn from(value: coins_ledger::LedgerError) -> Self { + Self::TransportError(value) + } +} + +impl From for APDUCommand { + fn from(_value: GetVersion) -> Self { + Self { + cla: CLA_STARKNET, + ins: 0x00, + p1: 0x00, + p2: 0x00, + data: APDUData::new(&[]), + response_len: None, + } + } +} + +impl From for APDUCommand { + fn from(value: GetPubKeyCommand) -> Self { + let path = value + .path + .iter() + .flat_map(|level| level.to_be_bytes()) + .collect::>(); + + Self { + cla: CLA_STARKNET, + ins: 0x01, + p1: if value.display { 0x01 } else { 0x00 }, + p2: 0x00, + data: APDUData::new(&path), + response_len: None, + } + } +} + +impl From for APDUCommand { + fn from(value: SignHashCommand1) -> Self { + let path = value + .path + .iter() + .flat_map(|level| level.to_be_bytes()) + .collect::>(); + + Self { + cla: CLA_STARKNET, + ins: 0x02, + p1: 0x00, + p2: 0x00, + data: APDUData::new(&path), + response_len: None, + } + } +} + +impl From for APDUCommand { + fn from(value: SignHashCommand2) -> Self { + // For some reasons, the Ledger app expects the input to be left shifted by 4 bits... + let shifted_bytes: [u8; 32] = (U256::from_be_slice(&value.hash) << 4) + .to_be_byte_array() + .into(); + + Self { + cla: CLA_STARKNET, + ins: 0x02, + p1: 0x01, + p2: 0x00, + data: APDUData::new(&shifted_bytes), + response_len: None, + } + } +} + +fn get_apdu_data(answer: &APDUAnswer) -> Result<&[u8], LedgerError> { + let ret_code = answer.retcode(); + + match TryInto::::try_into(ret_code) { + Ok(status) => { + if status.is_success() { + // Unwrapping here as we've already checked success + Ok(answer.data().unwrap()) + } else { + Err(LedgerError::UnsuccessfulRequest(status)) + } + } + Err(_) => Err(LedgerError::UnknownResponseCode(ret_code)), + } +} diff --git a/starknet-signers/src/lib.rs b/starknet-signers/src/lib.rs index 241dab3d..50903fab 100644 --- a/starknet-signers/src/lib.rs +++ b/starknet-signers/src/lib.rs @@ -10,5 +10,10 @@ pub use signer::Signer; pub mod local_wallet; pub use local_wallet::LocalWallet; +#[cfg(feature = "ledger")] +pub mod ledger; +#[cfg(feature = "ledger")] +pub use ledger::{DerivationPath, LedgerError, LedgerSigner}; + #[derive(Debug, thiserror::Error)] pub enum Infallible {} diff --git a/starknet-signers/src/local_wallet.rs b/starknet-signers/src/local_wallet.rs index c4ce3778..2c898da0 100644 --- a/starknet-signers/src/local_wallet.rs +++ b/starknet-signers/src/local_wallet.rs @@ -3,7 +3,7 @@ use crate::{Infallible, Signer, SigningKey, VerifyingKey}; use async_trait::async_trait; use starknet_core::{ crypto::{EcdsaSignError, Signature}, - types::FieldElement, + types::Felt, }; #[derive(Debug, Clone)] @@ -33,9 +33,13 @@ impl Signer for LocalWallet { Ok(self.private_key.verifying_key()) } - async fn sign_hash(&self, hash: &FieldElement) -> Result { + async fn sign_hash(&self, hash: &Felt) -> Result { Ok(self.private_key.sign(hash)?) } + + fn is_interactive(&self) -> bool { + false + } } impl From for LocalWallet { diff --git a/starknet-signers/src/signer.rs b/starknet-signers/src/signer.rs index 777d3a3a..429efede 100644 --- a/starknet-signers/src/signer.rs +++ b/starknet-signers/src/signer.rs @@ -2,7 +2,7 @@ use crate::VerifyingKey; use async_trait::async_trait; use auto_impl::auto_impl; -use starknet_core::{crypto::Signature, types::FieldElement}; +use starknet_core::{crypto::Signature, types::Felt}; use std::error::Error; #[cfg_attr(not(target_arch = "wasm32"), async_trait)] @@ -14,5 +14,15 @@ pub trait Signer { async fn get_public_key(&self) -> Result; - async fn sign_hash(&self, hash: &FieldElement) -> Result; + async fn sign_hash(&self, hash: &Felt) -> Result; + + /// Whether the underlying signer implementation is interactive, such as a hardware wallet. + /// Implementations should return `true` if the signing operation is very expensive, even if not + /// strictly "interactive" as in requiring human input. + /// + /// This mainly affects the transaction simulation strategy used by higher-level types. With + /// non-interactive signers, it's fine to sign multiple times for getting the most accurate + /// estimation/simulation possible; but with interactive signers, they would accept less + /// accurate results to minimize signing requests. + fn is_interactive(&self) -> bool; } diff --git a/tests/macros.rs b/tests/macros.rs index b9fafae4..9bc25193 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -1,6 +1,6 @@ use starknet::{ core::{ - types::FieldElement, + types::Felt, utils::{cairo_short_string_to_felt, get_selector_from_name}, }, macros::{felt, felt_dec, felt_hex, selector, short_string}, @@ -28,7 +28,7 @@ fn short_string_can_generate_correct_short_string() { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn felt_with_dec_string() { let macro_value = felt!("1234567"); - let function_call_value = FieldElement::from_dec_str("1234567").unwrap(); + let function_call_value = Felt::from_dec_str("1234567").unwrap(); assert_eq!(macro_value, function_call_value); } @@ -37,7 +37,7 @@ fn felt_with_dec_string() { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn felt_with_hex_string() { let macro_value = felt!("0x123456789abcdef"); - let function_call_value = FieldElement::from_hex_be("0x123456789abcdef").unwrap(); + let function_call_value = Felt::from_hex("0x123456789abcdef").unwrap(); assert_eq!(macro_value, function_call_value); } @@ -46,7 +46,7 @@ fn felt_with_hex_string() { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn felt_dec() { let macro_value = felt_dec!("1234567"); - let function_call_value = FieldElement::from_dec_str("1234567").unwrap(); + let function_call_value = Felt::from_dec_str("1234567").unwrap(); assert_eq!(macro_value, function_call_value); } @@ -55,7 +55,7 @@ fn felt_dec() { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn felt_hex() { let macro_value = felt_hex!("0x123456789abcdef"); - let function_call_value = FieldElement::from_hex_be("0x123456789abcdef").unwrap(); + let function_call_value = Felt::from_hex("0x123456789abcdef").unwrap(); assert_eq!(macro_value, function_call_value); }