diff --git a/.env.example b/.env.example index ff0a5a8f..f0e4ef0f 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,9 @@ -WORLDCHAIN_RPC_URL=https://worldchain-mainnet.g.alchemy.com/public # substitute with your own RPC in case of rate limits \ No newline at end of file +WORLDCHAIN_RPC_URL=https://worldchain-mainnet.g.alchemy.com/public # substitute with your own RPC in case of rate limits + +# E2E +WORLDCHAIN_RPC_URL_SEPOLIA= +TESTNET_NULLIFIER= +TESTNET_TRAPDOOR= +# No 0x +TESTNET_PRIVATE_KEY= +TESTNET_SAFE_ADDRESS= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 83b6bca0..e1844ec9 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,6 @@ kotlin/bedrock-tests/bin/ # foundry -out/ \ No newline at end of file +out/ + +sepolia_secrets.json \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index db1e6dca..bc9932ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,18 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "allocator-api2" version = "0.2.21" @@ -31,12 +43,14 @@ checksum = "5ecf116474faea3e30ecb03cb14548598ca8243d5316ce50f820e67b3e848473" dependencies = [ "alloy-consensus", "alloy-contract", - "alloy-core", + "alloy-core 1.2.1", "alloy-eips", "alloy-network", "alloy-node-bindings", "alloy-provider", "alloy-rpc-client", + "alloy-rpc-types", + "alloy-serde", "alloy-signer", "alloy-signer-aws", "alloy-signer-gcp", @@ -52,7 +66,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5848366a4f08dca1caca0a6151294a4799fe2e59ba25df100491d92e0b921b1c" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.3.1", "num_enum", "strum", ] @@ -64,7 +78,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b6093bc69509849435a2d68237a2e9fea79d27390c8e62f1e4012c460aabad8" dependencies = [ "alloy-eips", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-rlp", "alloy-serde", "alloy-trie", @@ -90,7 +104,7 @@ checksum = "8d1cfed4fefd13b5620cb81cdb6ba397866ff0de514c1b24806e6e79cdff5570" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-rlp", "alloy-serde", "serde", @@ -107,10 +121,10 @@ dependencies = [ "alloy-json-abi", "alloy-network", "alloy-network-primitives", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-provider", "alloy-rpc-types-eth", - "alloy-sol-types", + "alloy-sol-types 1.2.1", "alloy-transport", "futures", "futures-util", @@ -118,6 +132,16 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "alloy-core" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d8bcce99ad10fe02640cfaec1c6bc809b837c783c1d52906aa5af66e2a196f6" +dependencies = [ + "alloy-primitives 0.8.25", + "alloy-sol-types 0.8.25", +] + [[package]] name = "alloy-core" version = "1.2.1" @@ -126,8 +150,8 @@ checksum = "ad31216895d27d307369daa1393f5850b50bbbd372478a9fa951c095c210627e" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", - "alloy-primitives", - "alloy-sol-types", + "alloy-primitives 1.3.1", + "alloy-sol-types 1.2.1", ] [[package]] @@ -137,9 +161,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b95b3deca680efc7e9cba781f1a1db352fa1ea50e6384a514944dcf4419e652" dependencies = [ "alloy-json-abi", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-sol-type-parser", - "alloy-sol-types", + "alloy-sol-types 1.2.1", "derive_more", "itoa", "serde", @@ -153,7 +177,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "741bdd7499908b3aa0b159bba11e71c8cddd009a2c2eb7a06e825f1ec87900a5" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-rlp", "crc", "serde", @@ -166,7 +190,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b82752a889170df67bbb36d42ca63c531eb16274f0d7299ae2a680facba17bd" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-rlp", "serde", ] @@ -177,7 +201,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d4769c6ffddca380b0070d71c8b7f30bed375543fe76bb2f74ec0acf4b7cd16" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-rlp", "serde", "thiserror 2.0.12", @@ -192,7 +216,7 @@ dependencies = [ "alloy-eip2124", "alloy-eip2930", "alloy-eip7702", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-rlp", "alloy-serde", "auto_impl", @@ -210,7 +234,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c51b4c13e02a8104170a4de02ccf006d7c233e6c10ab290ee16e7041e6ac221d" dependencies = [ "alloy-eips", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-serde", "alloy-trie", "serde", @@ -224,7 +248,7 @@ checksum = "b40cc82a2283e3ce6317bc1f0134ea50d20e8c1965393045ee952fb28a65ddbd" dependencies = [ "alloy-chains", "alloy-eip2124", - "alloy-primitives", + "alloy-primitives 1.3.1", "auto_impl", "dyn-clone", ] @@ -235,7 +259,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15516116086325c157c18261d768a20677f0f699348000ed391d4ad0dcb82530" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-sol-type-parser", "serde", "serde_json", @@ -247,8 +271,8 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b590caa6b6d8bc10e6e7a7696c59b1e550e89f27f50d1ee13071150d3a3e3f66" dependencies = [ - "alloy-primitives", - "alloy-sol-types", + "alloy-primitives 1.3.1", + "alloy-sol-types 1.2.1", "http 1.3.1", "serde", "serde_json", @@ -267,12 +291,12 @@ dependencies = [ "alloy-eips", "alloy-json-rpc", "alloy-network-primitives", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-rpc-types-any", "alloy-rpc-types-eth", "alloy-serde", "alloy-signer", - "alloy-sol-types", + "alloy-sol-types 1.2.1", "async-trait", "auto_impl", "derive_more", @@ -290,7 +314,7 @@ checksum = "793df1e3457573877fbde8872e4906638fde565ee2d3bd16d04aad17d43dbf0e" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-serde", "serde", ] @@ -304,7 +328,7 @@ dependencies = [ "alloy-genesis", "alloy-hardforks", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-signer", "alloy-signer-local", "k256", @@ -318,9 +342,25 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.2.1" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c77490fe91a0ce933a1f219029521f20fc28c2c0ca95d53fa4da9c00b8d9d4e" +dependencies = [ + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "itoa", + "paste", + "ruint", + "tiny-keccak", +] + +[[package]] +name = "alloy-primitives" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6177ed26655d4e84e00b65cb494d4e0b8830e7cae7ef5d63087d445a2600fb55" +checksum = "bc9485c56de23438127a731a6b4c87803d49faf1a7068dcd1d8768aca3a9edb9" dependencies = [ "alloy-rlp", "bytes", @@ -356,12 +396,12 @@ dependencies = [ "alloy-network", "alloy-network-primitives", "alloy-node-bindings", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-rpc-client", "alloy-rpc-types-anvil", "alloy-rpc-types-eth", "alloy-signer", - "alloy-sol-types", + "alloy-sol-types 1.2.1", "alloy-transport", "alloy-transport-http", "async-stream", @@ -375,7 +415,7 @@ dependencies = [ "lru", "parking_lot", "pin-project 1.1.10", - "reqwest", + "reqwest 0.12.23", "serde", "serde_json", "thiserror 2.0.12", @@ -414,12 +454,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f060e3bb9f319eb01867a2d6d1ff9e0114e8877f5ca8f5db447724136106cae" dependencies = [ "alloy-json-rpc", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-transport", "alloy-transport-http", "futures", "pin-project 1.1.10", - "reqwest", + "reqwest 0.12.23", "serde", "serde_json", "tokio", @@ -430,13 +470,25 @@ dependencies = [ "wasmtimer", ] +[[package]] +name = "alloy-rpc-types" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d47b637369245d2dafef84b223b1ff5ea59e6cd3a98d2d3516e32788a0b216df" +dependencies = [ + "alloy-primitives 1.3.1", + "alloy-rpc-types-eth", + "alloy-serde", + "serde", +] + [[package]] name = "alloy-rpc-types-anvil" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0b1f499acb3fc729615147bc113b8b798b17379f19d43058a687edc5792c102" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-rpc-types-eth", "alloy-serde", "serde", @@ -463,10 +515,10 @@ dependencies = [ "alloy-consensus-any", "alloy-eips", "alloy-network-primitives", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-rlp", "alloy-serde", - "alloy-sol-types", + "alloy-sol-types 1.2.1", "itertools 0.14.0", "serde", "serde_json", @@ -480,7 +532,7 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e1722bc30feef87cc0fa824e43c9013f9639cc6c037be7be28a31361c788be2" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.3.1", "serde", "serde_json", ] @@ -492,8 +544,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3674beb29e68fbbc7be302b611cf35fe07b736e308012a280861df5a2361395" dependencies = [ "alloy-dyn-abi", - "alloy-primitives", - "alloy-sol-types", + "alloy-primitives 1.3.1", + "alloy-sol-types 1.2.1", "async-trait", "auto_impl", "either", @@ -510,7 +562,7 @@ checksum = "605b1659b320b16708bb84b41038b2f0e2a60d90972c28319c4f5a4866f0efd4" dependencies = [ "alloy-consensus", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-signer", "async-trait", "aws-sdk-kms", @@ -528,7 +580,7 @@ checksum = "0a207671ef0bf6f61e9c80c9ccb6d203439071252fb35886d6a89aae5431cd9c" dependencies = [ "alloy-consensus", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-signer", "async-trait", "gcloud-sdk", @@ -547,9 +599,9 @@ dependencies = [ "alloy-consensus", "alloy-dyn-abi", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-signer", - "alloy-sol-types", + "alloy-sol-types 1.2.1", "async-trait", "coins-ledger", "futures-util", @@ -566,7 +618,7 @@ checksum = "ad7094c39cd41b03ed642145b0bd37251e31a9cf2ed19e1ce761f089867356a6" dependencies = [ "alloy-consensus", "alloy-network", - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-signer", "async-trait", "k256", @@ -574,18 +626,50 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "alloy-sol-macro" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10ae8e9a91d328ae954c22542415303919aabe976fe7a92eb06db1b68fd59f2" +dependencies = [ + "alloy-sol-macro-expander 0.8.25", + "alloy-sol-macro-input 0.8.25", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "alloy-sol-macro" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a14f21d053aea4c6630687c2f4ad614bed4c81e14737a9b904798b24f30ea849" dependencies = [ - "alloy-sol-macro-expander", - "alloy-sol-macro-input", + "alloy-sol-macro-expander 1.2.1", + "alloy-sol-macro-input 1.2.1", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83ad5da86c127751bc607c174d6c9fe9b85ef0889a9ca0c641735d77d4f98f26" +dependencies = [ + "alloy-sol-macro-input 0.8.25", + "const-hex", + "heck", + "indexmap 2.9.0", "proc-macro-error2", "proc-macro2", "quote", "syn 2.0.104", + "syn-solidity 0.8.25", + "tiny-keccak", ] [[package]] @@ -595,7 +679,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34d99282e7c9ef14eb62727981a985a01869e586d1dec729d3bb33679094c100" dependencies = [ "alloy-json-abi", - "alloy-sol-macro-input", + "alloy-sol-macro-input 1.2.1", "const-hex", "heck", "indexmap 2.9.0", @@ -603,10 +687,26 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.104", - "syn-solidity", + "syn-solidity 1.2.1", "tiny-keccak", ] +[[package]] +name = "alloy-sol-macro-input" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3d30f0d3f9ba3b7686f3ff1de9ee312647aac705604417a2f40c604f409a9e" +dependencies = [ + "const-hex", + "dunce", + "heck", + "macro-string", + "proc-macro2", + "quote", + "syn 2.0.104", + "syn-solidity 0.8.25", +] + [[package]] name = "alloy-sol-macro-input" version = "1.2.1" @@ -622,7 +722,7 @@ dependencies = [ "quote", "serde_json", "syn 2.0.104", - "syn-solidity", + "syn-solidity 1.2.1", ] [[package]] @@ -635,6 +735,17 @@ dependencies = [ "winnow", ] +[[package]] +name = "alloy-sol-types" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43d5e60466a440230c07761aa67671d4719d46f43be8ea6e7ed334d8db4a9ab" +dependencies = [ + "alloy-primitives 0.8.25", + "alloy-sol-macro 0.8.25", + "const-hex", +] + [[package]] name = "alloy-sol-types" version = "1.2.1" @@ -642,8 +753,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58377025a47d8b8426b3e4846a251f2c1991033b27f517aade368146f6ab1dfe" dependencies = [ "alloy-json-abi", - "alloy-primitives", - "alloy-sol-macro", + "alloy-primitives 1.3.1", + "alloy-sol-macro 1.2.1", "serde", ] @@ -654,8 +765,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f89bec2f59a41c0e259b6fe92f78dfc49862c17d10f938db9c33150d5a7f42b6" dependencies = [ "alloy-json-rpc", - "alloy-primitives", - "base64", + "alloy-primitives 1.3.1", + "base64 0.22.1", "derive_more", "futures", "futures-utils-wasm", @@ -678,7 +789,7 @@ checksum = "0d3615ec64d775fec840f4e9d5c8e1f739eb1854d8d28db093fb3d4805e0cb53" dependencies = [ "alloy-json-rpc", "alloy-transport", - "reqwest", + "reqwest 0.12.23", "serde_json", "tower", "tracing", @@ -691,7 +802,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bada1fc392a33665de0dc50d401a3701b62583c655e3522a323490a5da016962" dependencies = [ - "alloy-primitives", + "alloy-primitives 1.3.1", "alloy-rlp", "arrayvec", "derive_more", @@ -707,8 +818,8 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f916ff6d52f219c44a9684aea764ce2c7e1d53bd4a724c9b127863aeacc30bb" dependencies = [ - "alloy-primitives", - "darling", + "alloy-primitives 1.3.1", + "darling 0.20.11", "proc-macro2", "quote", "syn 2.0.104", @@ -741,6 +852,54 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-crypto-primitives" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56" +dependencies = [ + "ark-ec", + "ark-ff 0.4.2", + "ark-relations", + "ark-serialize 0.4.2", + "ark-snark", + "ark-std 0.4.0", + "blake2", + "derivative", + "digest 0.10.7", + "rayon", + "sha2", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff 0.4.2", + "ark-poly", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "rayon", + "zeroize", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -775,6 +934,7 @@ dependencies = [ "num-bigint", "num-traits", "paste", + "rayon", "rustc_version 0.4.1", "zeroize", ] @@ -824,6 +984,48 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-groth16" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20ceafa83848c3e390f1cbf124bc3193b3e639b3f02009e0e290809a501b95fc" +dependencies = [ + "ark-crypto-primitives", + "ark-ec", + "ark-ff 0.4.2", + "ark-poly", + "ark-relations", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "rayon", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", + "rayon", +] + +[[package]] +name = "ark-relations" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" +dependencies = [ + "ark-ff 0.4.2", + "ark-std 0.4.0", + "tracing", + "tracing-subscriber 0.2.25", +] + [[package]] name = "ark-serialize" version = "0.3.0" @@ -840,11 +1042,35 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ + "ark-serialize-derive", "ark-std 0.4.0", "digest 0.10.7", "num-bigint", ] +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-snark" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63" +dependencies = [ + "ark-ff 0.4.2", + "ark-relations", + "ark-serialize 0.4.2", + "ark-std 0.4.0", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -863,6 +1089,7 @@ checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", "rand 0.8.5", + "rayon", ] [[package]] @@ -975,6 +1202,15 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -1224,7 +1460,7 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper", + "sync_wrapper 1.0.2", "tower", "tower-layer", "tower-service", @@ -1244,7 +1480,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", ] @@ -1270,6 +1506,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -1306,26 +1548,36 @@ name = "bedrock" version = "0.0.6" dependencies = [ "alloy", + "alloy-primitives 1.3.1", + "alloy-rlp", "anyhow", "async-trait", "bedrock-macros", + "bon", "chrono", "dotenvy", + "futures", "hex", "log", "proc-macro2", "quote", - "rand 0.8.5", + "rand 0.9.2", + "reqwest 0.12.23", "ruint", "secrecy", + "semaphore-rs", + "semaphore-rs-proof", "serde", "serde_json", + "strum", "subtle", "syn 2.0.104", + "test-case", "thiserror 2.0.12", "tokio", "tokio-test", "uniffi", + "world-chain-builder-pbh", "zeroize", ] @@ -1338,6 +1590,15 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bit-set" version = "0.8.0" @@ -1393,6 +1654,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -1414,6 +1684,31 @@ dependencies = [ "zeroize", ] +[[package]] +name = "bon" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537c317ddf588aab15c695bf92cf55dec159b93221c074180ca3e0e5a94da415" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5abbf2d4a4c6896197c9de13d6d7cb7eff438c63dacde1dde980569cb00248" +dependencies = [ + "darling 0.21.3", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.104", +] + [[package]] name = "bumpalo" version = "3.17.0" @@ -1426,6 +1721,12 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" +[[package]] +name = "bytemuck" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" + [[package]] name = "byteorder" version = "1.5.0" @@ -1527,8 +1828,10 @@ checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", "windows-link", ] @@ -1571,6 +1874,26 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.12", +] + +[[package]] +name = "codespan-reporting" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + [[package]] name = "coins-ledger" version = "0.12.0" @@ -1594,6 +1917,43 @@ dependencies = [ "wasm-bindgen-futures", ] +[[package]] +name = "color-eyre" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "const-hex" version = "1.14.1" @@ -1635,7 +1995,17 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.10.1" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ @@ -1682,6 +2052,31 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -1716,14 +2111,39 @@ dependencies = [ "typenum", ] +[[package]] +name = "cxx-build" +version = "1.0.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acef58f684c0c9b7bffc111657c9f1364e4fa47af46fd7f03b71b7a4066ac372" +dependencies = [ + "cc", + "codespan-reporting", + "indexmap 2.9.0", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.104", +] + [[package]] name = "darling" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", ] [[package]] @@ -1740,13 +2160,38 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.104", +] + [[package]] name = "darling_macro" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core", + "darling_core 0.20.11", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", "quote", "syn 2.0.104", ] @@ -1797,6 +2242,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive-where" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "derive_more" version = "2.0.1" @@ -1913,6 +2369,39 @@ dependencies = [ "zeroize", ] +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1929,6 +2418,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -2001,6 +2500,21 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -2130,12 +2644,12 @@ dependencies = [ "bytes", "chrono", "futures", - "hyper", + "hyper 1.6.0", "jsonwebtoken", "once_cell", "prost", "prost-types", - "reqwest", + "reqwest 0.12.23", "secret-vault-value", "serde", "serde_json", @@ -2220,6 +2734,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.9.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "h2" version = "0.4.10" @@ -2239,12 +2772,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -2263,6 +2814,20 @@ dependencies = [ "serde", ] +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version 0.4.1", + "serde", + "spin", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.5.0" @@ -2293,6 +2858,12 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "hidapi-rusb" version = "1.3.3" @@ -2382,6 +2953,30 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.9", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.6.0" @@ -2391,7 +2986,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2", + "h2 0.4.10", "http 1.3.1", "http-body 1.0.1", "httparse", @@ -2410,7 +3005,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" dependencies = [ "http 1.3.1", - "hyper", + "hyper 1.6.0", "hyper-util", "rustls", "rustls-native-certs", @@ -2418,7 +3013,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.0", + "webpki-roots", ] [[package]] @@ -2427,31 +3022,65 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper", + "hyper 1.6.0", "hyper-util", "pin-project-lite", "tokio", "tower-service", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.32", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.6.0", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9f1e950e0d9d1d3c47184416723cf29c0d1f93bd8cccf37e4beb6b44f31710" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", "futures-util", "http 1.3.1", "http-body 1.0.1", - "hyper", + "hyper 1.6.0", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2 0.5.9", + "system-configuration 0.6.1", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -2611,6 +3240,12 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "indenter" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" + [[package]] name = "indexmap" version = "1.9.3" @@ -2650,6 +3285,16 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "itertools" version = "0.10.5" @@ -2659,6 +3304,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -2690,7 +3344,7 @@ version = "9.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" dependencies = [ - "base64", + "base64 0.22.1", "js-sys", "pem", "ring", @@ -2805,6 +3459,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + [[package]] name = "macro-string" version = "0.1.4" @@ -2828,6 +3491,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memmap2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.7.1" @@ -2879,6 +3551,40 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "mmap-rs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86968d85441db75203c34deefd0c88032f275aaa85cee19a1dcfff6ae9df56da" +dependencies = [ + "bitflags 1.3.2", + "combine", + "libc", + "mach2", + "nix", + "sysctl", + "thiserror 1.0.69", + "widestring", + "windows", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nix" version = "0.26.4" @@ -2910,6 +3616,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", + "rand 0.8.5", ] [[package]] @@ -2997,17 +3704,61 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] -name = "openssl-probe" -version = "0.1.6" +name = "openssl" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] name = "outref" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" +[[package]] +name = "owo-colors" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48dd4f4a2c8405440fd0462561f0e5806bd0f77e86f51c761481bdd4018b545e" + [[package]] name = "parity-scale-codec" version = "3.7.5" @@ -3071,7 +3822,7 @@ version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" dependencies = [ - "base64", + "base64 0.22.1", "serde", ] @@ -3175,6 +3926,19 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "heapless", + "serde", +] + [[package]] name = "potential_utf" version = "0.1.2" @@ -3199,6 +3963,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" +dependencies = [ + "proc-macro2", + "syn 2.0.104", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -3455,6 +4229,26 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.5.12" @@ -3478,50 +4272,92 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.15" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-tls 0.5.0", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration 0.5.1", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "reqwest" +version = "0.12.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" dependencies = [ "async-compression", - "base64", + "base64 0.22.1", "bytes", + "encoding_rs", "futures-core", "futures-util", + "h2 0.4.10", "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.6.0", "hyper-rustls", + "hyper-tls 0.6.0", "hyper-util", - "ipnet", "js-sys", "log", "mime", "mime_guess", - "once_cell", + "native-tls", "percent-encoding", "pin-project-lite", "quinn", "rustls", "rustls-native-certs", - "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.2", "tokio", + "tokio-native-tls", "tokio-rustls", "tokio-util", "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.26.11", - "windows-registry", + "webpki-roots", ] [[package]] @@ -3567,6 +4403,7 @@ dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", + "bytemuck", "bytes", "fastrlp 0.3.1", "fastrlp 0.4.0", @@ -3674,16 +4511,16 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 3.2.0", ] [[package]] name = "rustls-pemfile" -version = "2.2.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "rustls-pki-types", + "base64 0.21.7", ] [[package]] @@ -3731,6 +4568,15 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.27" @@ -3746,6 +4592,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scratch" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68f2ec51b097e4c1a75b681a8bec621909b5e91f15bb7b840c4f2f7b01148b2" + [[package]] name = "scroll" version = "0.12.0" @@ -3825,6 +4677,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.1", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + [[package]] name = "security-framework" version = "3.2.0" @@ -3832,7 +4697,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ "bitflags 2.9.1", - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -3848,6 +4713,234 @@ dependencies = [ "libc", ] +[[package]] +name = "semaphore-rs" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b47ba971a6088a498d78316854aab2f3833ca031722d369378220cdbbc75ca2" +dependencies = [ + "alloy-core 0.8.25", + "ark-bn254", + "ark-ec", + "ark-ff 0.4.2", + "ark-groth16", + "ark-relations", + "ark-std 0.4.0", + "bincode", + "bytemuck", + "color-eyre", + "hex", + "hex-literal", + "itertools 0.13.0", + "lazy_static", + "mmap-rs", + "num-bigint", + "once_cell", + "rand 0.8.5", + "rayon", + "reqwest 0.11.27", + "ruint", + "semaphore-rs-ark-circom", + "semaphore-rs-ark-zkey", + "semaphore-rs-depth-config", + "semaphore-rs-depth-macros", + "semaphore-rs-hasher", + "semaphore-rs-keccak", + "semaphore-rs-poseidon", + "semaphore-rs-proof", + "semaphore-rs-storage", + "semaphore-rs-trees", + "semaphore-rs-utils", + "semaphore-rs-witness", + "serde", + "sha2", + "thiserror 1.0.69", + "tiny-keccak", + "zeroize", +] + +[[package]] +name = "semaphore-rs-ark-circom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "590c00fa015e2f7f03f4f0f4123bbe38a7cded0f4497cdd67b7874e8a37887f3" +dependencies = [ + "ark-bn254", + "ark-crypto-primitives", + "ark-ff 0.4.2", + "ark-groth16", + "ark-poly", + "ark-relations", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "byteorder", + "num-bigint", + "num-traits", + "ruint", + "serde_json", +] + +[[package]] +name = "semaphore-rs-ark-zkey" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c5486a113b07b9f4c003a81f4efaca98159498bb7acff34b3b8c6fb022132b" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff 0.4.2", + "ark-groth16", + "ark-relations", + "ark-serialize 0.4.2", + "color-eyre", + "memmap2", + "semaphore-rs-ark-circom", +] + +[[package]] +name = "semaphore-rs-depth-config" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b250534726c9a2785bfb8fcb498540ef47fb0f732824bb640994dcaa40547f6" + +[[package]] +name = "semaphore-rs-depth-macros" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fa8ad8e24071abbc3c554db3c940e2af2dd676259ab702b8b7f516d162986fb" +dependencies = [ + "itertools 0.13.0", + "proc-macro2", + "quote", + "semaphore-rs-depth-config", + "syn 2.0.104", +] + +[[package]] +name = "semaphore-rs-hasher" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11442fee48d178242d0e22715253821fb23ee0a770cf7ce3d13079718f4231e9" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "semaphore-rs-keccak" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d5efcb970e069bd434c7dc1dad4d715e0ec9208c10d66d81076cc5d57f7b78" +dependencies = [ + "semaphore-rs-hasher", + "tiny-keccak", +] + +[[package]] +name = "semaphore-rs-poseidon" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d26e9b66d2fcf52621d2d86786bca4e09f080c902d6c9f53587bb3c97dd812e" +dependencies = [ + "ark-bn254", + "ark-ff 0.4.2", + "once_cell", + "ruint", + "semaphore-rs-hasher", +] + +[[package]] +name = "semaphore-rs-proof" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bf4c50a78e3ce61761e6c5bdd21f1f640845cf416bc4d9705f0657c3b1a931" +dependencies = [ + "alloy-core 0.8.25", + "ark-bn254", + "ark-ec", + "ark-groth16", + "getrandom 0.2.16", + "hex", + "lazy_static", + "ruint", + "semaphore-rs-ark-circom", + "semaphore-rs-utils", + "serde", + "serde_json", +] + +[[package]] +name = "semaphore-rs-storage" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7843420192065a5a4789285e984df9239a294e9553631717c03cbb66b141ff91" +dependencies = [ + "bytemuck", + "color-eyre", + "mmap-rs", + "tempfile", +] + +[[package]] +name = "semaphore-rs-trees" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a2bc89c277b8761b46ed6953a6995d01ecadb87164f5b499a2c67846ea517" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff 0.4.2", + "ark-groth16", + "ark-relations", + "ark-std 0.4.0", + "bytemuck", + "color-eyre", + "derive-where", + "hex", + "hex-literal", + "itertools 0.13.0", + "mmap-rs", + "once_cell", + "rayon", + "ruint", + "semaphore-rs-ark-circom", + "semaphore-rs-hasher", + "semaphore-rs-storage", + "serde", + "thiserror 1.0.69", + "tiny-keccak", +] + +[[package]] +name = "semaphore-rs-utils" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb67bdd9e07446957225c963228a4be98a60bf80389fbb335eda61e749a15306" +dependencies = [ + "hex", + "serde", + "tiny-keccak", +] + +[[package]] +name = "semaphore-rs-witness" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "014e1212ea105aa3be44b7c0d318234794dec47e23a926b088e742cfc9f89fa3" +dependencies = [ + "ark-bn254", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "byteorder", + "color-eyre", + "cxx-build", + "hex", + "postcard", + "rand 0.8.5", + "ruint", + "serde", + "serde_json", +] + [[package]] name = "semver" version = "0.11.0" @@ -3925,7 +5018,7 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ - "base64", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", @@ -3943,7 +5036,7 @@ version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ - "darling", + "darling 0.20.11", "proc-macro2", "quote", "syn 2.0.104", @@ -3990,6 +5083,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -4068,6 +5170,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "spki" version = "0.7.3" @@ -4098,9 +5209,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.27.1" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" dependencies = [ "strum_macros", ] @@ -4146,6 +5257,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn-solidity" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4560533fbd6914b94a8fb5cc803ed6801c3455668db3b810702c57612bac9412" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "syn-solidity" version = "1.2.1" @@ -4158,6 +5281,12 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -4178,6 +5307,62 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "sysctl" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7dddc5f0fee506baf8b9fdb989e242f17e4b11c61dfbb0635b705217199eea" +dependencies = [ + "bitflags 2.9.1", + "byteorder", + "enum-as-inner", + "libc", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.9.1", + "core-foundation 0.9.4", + "system-configuration-sys 0.6.0", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -4197,6 +5382,48 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "test-case" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" +dependencies = [ + "test-case-macros", +] + +[[package]] +name = "test-case-core" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "test-case-macros" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", + "test-case-core", +] + [[package]] name = "textwrap" version = "0.16.2" @@ -4246,6 +5473,15 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "threadpool" version = "1.8.1" @@ -4349,6 +5585,16 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.2" @@ -4431,13 +5677,13 @@ checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", - "h2", + "h2 0.4.10", "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.6.0", "hyper-timeout", "hyper-util", "percent-encoding", @@ -4465,7 +5711,7 @@ dependencies = [ "indexmap 2.9.0", "pin-project-lite", "slab", - "sync_wrapper", + "sync_wrapper 1.0.2", "tokio", "tokio-util", "tower-layer", @@ -4473,6 +5719,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.9.1", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -4526,6 +5790,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" +dependencies = [ + "tracing", + "tracing-subscriber 0.3.19", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", ] [[package]] @@ -4576,6 +5871,12 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-width" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -4789,6 +6090,16 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -4931,15 +6242,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.0", -] - [[package]] name = "webpki-roots" version = "1.0.0" @@ -4958,6 +6260,30 @@ dependencies = [ "nom", ] +[[package]] +name = "widestring" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" + +[[package]] +name = "winapi-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-core" version = "0.61.2" @@ -5007,7 +6333,7 @@ checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ "windows-result", "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-targets 0.53.2", ] [[package]] @@ -5037,6 +6363,15 @@ dependencies = [ "windows-link", ] +[[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.5", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -5055,6 +6390,21 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -5073,9 +6423,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" dependencies = [ "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", @@ -5087,6 +6437,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -5099,6 +6455,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -5111,6 +6473,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -5135,6 +6503,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -5147,6 +6521,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -5159,6 +6539,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -5171,6 +6557,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -5192,6 +6584,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "wit-bindgen-rt" version = "0.39.0" @@ -5201,6 +6603,22 @@ dependencies = [ "bitflags 2.9.1", ] +[[package]] +name = "world-chain-builder-pbh" +version = "0.1.0" +source = "git+https://github.com/worldcoin/world-chain?rev=4f524c6#4f524c699735a1d30932a22914c8abe3a4b40ac3" +dependencies = [ + "alloy-primitives 1.3.1", + "alloy-rlp", + "bon", + "chrono", + "semaphore-rs", + "semaphore-rs-proof", + "serde", + "strum", + "thiserror 1.0.69", +] + [[package]] name = "writeable" version = "0.6.1" diff --git a/bedrock/Cargo.toml b/bedrock/Cargo.toml index 58cd0966..8d3682fa 100644 --- a/bedrock/Cargo.toml +++ b/bedrock/Cargo.toml @@ -23,31 +23,48 @@ tooling_tests = ["dep:tokio"] [dependencies] alloy = { version = "1.0.23", default-features = false, features = [ - "dyn-abi", - "eip712", - "signer-local", - "sol-types", + "dyn-abi", + "eip712", + "signer-local", + "sol-types", + "rpc", + "rpc-types", + "providers", + "network", + "contract", ] } +alloy-primitives = "1.3.1" +alloy-rlp = "0.3.12" anyhow = "1.0" async-trait = "0.1" bedrock-macros = { path = "../bedrock-macros" } -chrono = { version = "0.4.41", default-features = false, features = ["now", "std"] } +bon = "3.7.1" +chrono = { version = "0.4.41", default-features = false, features = [ + "now", + "std", +] } +futures = "0.3.31" hex = "0.4.3" log = "0.4.22" proc-macro2 = "1.0" quote = "1.0" -rand = "0.8.5" +rand = "0.9.2" +reqwest = { version = "0.12.19", features = ["json"] } ruint = { version = "1.15.0", default-features = false, features = ["serde"] } -secrecy = { version = "0.10", features = ["serde"] } +semaphore-rs = "0.3.1" +semaphore-rs-proof = "0.3.1" serde = "1.0.219" serde_json = "1.0" +strum = "0.27.1" +secrecy = { version = "0.10", features = ["serde"] } subtle = "2.6.1" syn = { version = "2.0", features = ["full"] } +test-case = "3.3.1" thiserror = "2.0.12" tokio = { version = "1.47.1", features = ["time"], optional = true } uniffi = { workspace = true, features = ["build", "tokio"] } +world-chain-builder-pbh = { git = "https://github.com/worldcoin/world-chain", rev = "4f524c6" } zeroize = "1.8" - [dev-dependencies] alloy = { version = "1.0.23", default-features = false, features = [ "json", diff --git a/bedrock/src/lib.rs b/bedrock/src/lib.rs index 01e769c9..0a91287f 100644 --- a/bedrock/src/lib.rs +++ b/bedrock/src/lib.rs @@ -3,7 +3,8 @@ clippy::pedantic, clippy::nursery, missing_docs, - dead_code + dead_code, + unused_imports )] //! `bedrock` is the foundational library which powers World App's crypto wallet diff --git a/bedrock/src/primitives/contracts.rs b/bedrock/src/primitives/contracts.rs index 9b983c89..93366337 100644 --- a/bedrock/src/primitives/contracts.rs +++ b/bedrock/src/primitives/contracts.rs @@ -1,11 +1,17 @@ +use crate::primitives::contracts::IEntryPoint::PackedUserOperation; +use crate::primitives::contracts::IPBHEntryPoint::PBHPayload; use crate::primitives::{HttpError, PrimitiveError}; use crate::transaction::rpc::SponsorUserOperationResponse; use alloy::hex::FromHex; use alloy::primitives::{aliases::U48, keccak256, Address, Bytes, FixedBytes}; use alloy::sol; use alloy::sol_types::SolValue; +use alloy_primitives::{U128, U64, U8}; use ruint::aliases::U256; +use serde::{Deserialize, Serialize}; use std::{str::FromStr, sync::LazyLock}; +use world_chain_builder_pbh::external_nullifier::EncodedExternalNullifier; +use world_chain_builder_pbh::payload::PBHPayload as WorldchainBuilderPBHPayload; /// static SAFE_OP_TYPEHASH: LazyLock> = LazyLock::new(|| { @@ -15,6 +21,20 @@ static SAFE_OP_TYPEHASH: LazyLock> = LazyLock::new(|| { .expect("error initializing `SAFE_OP_TYPEHASH`") }); +/// `PBHSignatureAggregator` - Sepolia +/// Contract reference: +pub static PBH_SIGNATURE_AGGREGATOR_SEPOLIA: LazyLock
= LazyLock::new(|| { + Address::from_str("0x8af27Ee9AF538C48C7D2a2c8BD6a40eF830e2489") + .expect("failed to decode PBH_SIGNATURE_AGGREGATOR_SEPOLIA") +}); + +/// `PBHSignatureAggregator` - Mainnet +/// Contract reference: +pub static PBH_SIGNATURE_AGGREGATOR_MAINNET: LazyLock
= LazyLock::new(|| { + Address::from_str("0xd21306c75c956142c73c0c3bab282be68595081e") + .expect("failed to decode PBH_SIGNATURE_AGGREGATOR_MAINNET") +}); + /// v0.7.0 `EntryPoint` contract /// Contract reference: pub static ENTRYPOINT_4337: LazyLock
= LazyLock::new(|| { @@ -22,18 +42,151 @@ pub static ENTRYPOINT_4337: LazyLock
= LazyLock::new(|| { .expect("failed to decode ENTRYPOINT_4337") }); +/// Address for `PBH_ENTRYPOINT_4337` - same on sepolia and mainnet +/// Contract reference: +pub static PBH_ENTRYPOINT_4337: LazyLock
= LazyLock::new(|| { + Address::from_str("0x0000000000A21818Ee9F93BB4f2AAad305b5397C") + .expect("failed to decode PBH_ENTRYPOINT_4337") +}); + /// Multichain address for the v0.3.0 `Safe4337Module` pub static GNOSIS_SAFE_4337_MODULE: LazyLock
= LazyLock::new(|| { Address::from_str("0x75cf11467937ce3f2f357ce24ffc3dbf8fd5c226") .expect("failed to decode GNOSIS_SAFE_4337_MODULE") }); +/// Contract reference: +pub static PBH_SAFE_4337_MODULE_SEPOLIA: LazyLock
= LazyLock::new(|| { + Address::from_str("0xeA5877676caC52d51DCEc80e4Ff33898d5B0E8D9") + .expect("failed to decode GNOSIS_SAFE_4337_MODULE") +}); + +/// Contract reference: +pub static PBH_SAFE_4337_MODULE_MAINNET: LazyLock
= LazyLock::new(|| { + Address::from_str("0xb5b2a890a5ED55B07A27d014AdaAC113A545a96c") + .expect("failed to decode GNOSIS_SAFE_4337_MODULE") +}); + /// The length of a 4337 `UserOperation` signature. /// /// This is the length of a regular ECDSA signature with r,s,v (32 + 32 + 1 = 65 bytes) + 12 bytes for the validity timestamps. const USER_OPERATION_SIGNATURE_LENGTH: usize = 77; +/// authorization tuple for 7702 txn support +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct RpcEip7702Auth { + /// The chain ID of the authorization. + pub chain_id: U64, + /// The address of the authorization. + pub address: Address, + /// The nonce for the authorization. + pub nonce: U64, + /// signed authorizzation tuple. + pub y_parity: U8, + /// signed authorizzation tuple. + pub r: U256, + /// signed authorizzation tuple. + pub s: U256, +} + +/// User operation definition for RPC inputs +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct RpcUserOperationV0_7 { + sender: Address, + nonce: U256, + call_data: Bytes, + call_gas_limit: U128, + verification_gas_limit: U128, + pre_verification_gas: U256, + max_priority_fee_per_gas: U128, + max_fee_per_gas: U128, + #[serde(skip_serializing_if = "Option::is_none")] + factory: Option
, + #[serde(skip_serializing_if = "Option::is_none")] + factory_data: Option, + #[serde(skip_serializing_if = "Option::is_none")] + paymaster: Option
, + #[serde(skip_serializing_if = "Option::is_none")] + paymaster_verification_gas_limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + paymaster_post_op_gas_limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + paymaster_data: Option, + signature: Bytes, + #[serde(skip_serializing_if = "Option::is_none")] + eip7702_auth: Option, + #[serde(skip_serializing_if = "Option::is_none")] + aggregator: Option
, +} + +#[allow(clippy::from_over_into)] +impl Into for (PackedUserOperation, Address) { + fn into(self) -> RpcUserOperationV0_7 { + let (user_op, aggregator) = self; + RpcUserOperationV0_7 { + sender: user_op.sender, + nonce: user_op.nonce, + factory: None, + call_data: user_op.callData, + factory_data: None, + verification_gas_limit: (U256::from_be_bytes( + user_op.accountGasLimits.into(), + ) >> U256::from(128)) + .to(), + call_gas_limit: (U256::from_be_bytes(user_op.accountGasLimits.into()) + & U256::from_str("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap()) + .to(), + pre_verification_gas: user_op.preVerificationGas, + max_priority_fee_per_gas: (U256::from_be_bytes(user_op.gasFees.into()) + >> U256::from(128)) + .to(), + max_fee_per_gas: (U256::from_be_bytes(user_op.gasFees.into()) + & U256::from_str("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap()) + .to(), + signature: user_op.signature, + paymaster: None, + paymaster_data: None, + paymaster_post_op_gas_limit: None, + paymaster_verification_gas_limit: None, + aggregator: Some(aggregator), + eip7702_auth: None, + } + } +} -// --- JSON serialization helpers for ERC-4337 --- +#[allow(clippy::from_over_into)] +impl Into for PackedUserOperation { + fn into(self) -> RpcUserOperationV0_7 { + RpcUserOperationV0_7 { + sender: self.sender, + nonce: self.nonce, + factory: None, + call_data: self.callData, + factory_data: None, + verification_gas_limit: (U256::from_be_bytes(self.accountGasLimits.into()) + >> U256::from(128)) + .to(), + call_gas_limit: (U256::from_be_bytes(self.accountGasLimits.into()) + & U256::from_str("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap()) + .to(), + pre_verification_gas: self.preVerificationGas, + max_priority_fee_per_gas: (U256::from_be_bytes(self.gasFees.into()) + >> U256::from(128)) + .to(), + max_fee_per_gas: (U256::from_be_bytes(self.gasFees.into()) + & U256::from_str("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap()) + .to(), + signature: self.signature, + paymaster: None, + paymaster_data: None, + paymaster_post_op_gas_limit: None, + paymaster_verification_gas_limit: None, + aggregator: None, + eip7702_auth: None, + } + } +} fn serialize_u128_as_hex( value: &u128, @@ -53,7 +206,6 @@ fn serialize_u256_as_hex( } sol! { - /// Interface for the `Safe4337Module` contract. /// /// Reference: @@ -308,6 +460,47 @@ impl EncodedSafeOpStruct { } } +impl From for IEntryPoint::PackedUserOperation { + /// Converts a `UserOperation` into a `PackedUserOperation`. + /// + /// This conversion packs gas limits and fees into bytes32 fields as required by EIP-4337. + /// - `accountGasLimits`: `verification_gas_limit` (upper 128 bits) + `call_gas_limit` (lower 128 bits) + /// - `gasFees`: `max_priority_fee_per_gas` (upper 128 bits) + `max_fee_per_gas` (lower 128 bits) + /// + /// # Example + /// ```rust + /// use bedrock::primitives::contracts::{UserOperation, IEntryPoint::PackedUserOperation}; + /// + /// let user_op = UserOperation::default(); + /// let packed_user_op: PackedUserOperation = user_op.into(); + /// ``` + fn from(user_op: UserOperation) -> Self { + // Pack verification_gas_limit (upper 128 bits) + call_gas_limit (lower 128 bits) into accountGasLimits + let verification_gas_u256 = U256::from(user_op.verification_gas_limit); + let call_gas_u256 = U256::from(user_op.call_gas_limit); + let account_gas_limits: U256 = (verification_gas_u256 << 128) | call_gas_u256; + + // Pack max_priority_fee_per_gas (upper 128 bits) + max_fee_per_gas (lower 128 bits) into gasFees + let max_priority_fee_u256 = U256::from(user_op.max_priority_fee_per_gas); + let max_fee_u256 = U256::from(user_op.max_fee_per_gas); + let gas_fees: U256 = (max_priority_fee_u256 << 128) | max_fee_u256; + + Self { + sender: user_op.sender, + nonce: user_op.nonce, + initCode: user_op.get_init_code(), + callData: user_op.call_data.clone(), + accountGasLimits: FixedBytes::from_slice( + &account_gas_limits.to_be_bytes::<32>(), + ), + preVerificationGas: user_op.pre_verification_gas, + gasFees: FixedBytes::from_slice(&gas_fees.to_be_bytes::<32>()), + paymasterAndData: user_op.get_paymaster_and_data(), + signature: user_op.signature, + } + } +} + sol! { contract IMulticall3 { #[derive(Default)] @@ -318,6 +511,7 @@ sol! { } } + #[sol(rpc)] contract IEntryPoint { #[derive(Default, serde::Serialize, serde::Deserialize, Debug)] struct PackedUserOperation { @@ -340,6 +534,7 @@ sol! { } } + #[sol(rpc)] contract IPBHEntryPoint { #[derive(Default)] struct PBHPayload { @@ -358,5 +553,32 @@ sol! { IMulticall3.Call3[] calls, PBHPayload payload, ) external; + + function getFirstUnspentNullifierHash(uint256[] calldata hashes) external view returns (int256); + + function getUnspentNullifierHashes(uint256[] calldata hashes) external view returns (uint256[] memory); + } +} + +impl From for PBHPayload { + fn from(val: WorldchainBuilderPBHPayload) -> Self { + let p0 = val.proof.0 .0 .0; + let p1 = val.proof.0 .0 .1; + let p2 = val.proof.0 .1 .0[0]; + let p3 = val.proof.0 .1 .0[1]; + let p4 = val.proof.0 .1 .1[0]; + let p5 = val.proof.0 .1 .1[1]; + let p6 = val.proof.0 .2 .0; + let p7 = val.proof.0 .2 .1; + + Self { + root: val.root, + pbhExternalNullifier: EncodedExternalNullifier::from( + val.external_nullifier, + ) + .0, + nullifierHash: val.nullifier_hash, + proof: [p0, p1, p2, p3, p4, p5, p6, p7], + } } } diff --git a/bedrock/src/primitives/mod.rs b/bedrock/src/primitives/mod.rs index 00821997..60e02c85 100644 --- a/bedrock/src/primitives/mod.rs +++ b/bedrock/src/primitives/mod.rs @@ -62,6 +62,9 @@ pub mod tooling_tests; /// Contract interfaces and data structures for ERC-4337 account abstraction pub mod contracts; +/// Introduces World ID identity functionality for Bedrock operations +pub mod world_id; + /// Supported blockchain networks for Bedrock operations #[derive(Debug, Clone, Copy, PartialEq, Eq, uniffi::Enum)] #[repr(u32)] @@ -72,6 +75,8 @@ pub enum Network { Optimism = 10, /// World Chain (chain ID: 480) WorldChain = 480, + /// World Chain Sepolia (chain ID: 4801) + WorldChainSepolia = 4801, } impl Network { @@ -82,6 +87,7 @@ impl Network { Self::Ethereum => "ethereum", Self::Optimism => "optimism", Self::WorldChain => "worldchain", + Self::WorldChainSepolia => "worldchain-sepolia", } } @@ -92,6 +98,7 @@ impl Network { Self::Ethereum => "Ethereum", Self::Optimism => "Optimism", Self::WorldChain => "World Chain", + Self::WorldChainSepolia => "World Chain Sepolia", } } } diff --git a/bedrock/src/primitives/world_id.rs b/bedrock/src/primitives/world_id.rs new file mode 100644 index 00000000..87dd7560 --- /dev/null +++ b/bedrock/src/primitives/world_id.rs @@ -0,0 +1,323 @@ +use alloy::sol_types::{SolCall, SolValue}; + +use alloy::primitives::Bytes; +use alloy_primitives::I256; +use chrono::{Datelike, Utc}; +use reqwest::Client; +use semaphore_rs::identity::Identity; +use semaphore_rs::poseidon_tree::Proof as PoseidonTreeProof; +use semaphore_rs::protocol::{generate_nullifier_hash, generate_proof, ProofError}; +use semaphore_rs::{hash_to_field, Field}; +use semaphore_rs_proof::Proof as SemaphoreProof; +use serde::{Deserialize, Serialize}; +use std::sync::{Arc, OnceLock}; +use world_chain_builder_pbh::{ + external_nullifier::{EncodedExternalNullifier, ExternalNullifier}, + payload::{ + PBHPayload as WorldchainBuilderPBHPayload, Proof as WorldchainBuilderProof, + }, +}; + +use crate::primitives::contracts::{IPBHEntryPoint, PBH_ENTRYPOINT_4337}; +use crate::primitives::Network; +use crate::transaction::rpc::get_rpc_client; +use crate::transaction::RpcError; +use crate::{ + primitives::contracts::IEntryPoint::PackedUserOperation, + smart_account::UserOperation, +}; + +use alloy::primitives::U256; + +const STAGING_SEQUENCER_URL: &str = + "https://signup-orb-ethereum.stage-crypto.worldcoin.dev"; +const PRODUCTION_SEQUENCER_URL: &str = + "https://signup-orb-ethereum.crypto.worldcoin.org"; + +const STAGING_MAX_NONCE: u16 = u16::MAX; +// TODO: UPDATE THIS ONCE SET IN PRODUCTION +const PRODUCTION_MAX_NONCE: u16 = 9000; + +const MAX_NONCE_BATCH_SIZE: u16 = 100; + +/// Inclusion proof for a given identity. +/// +/// This struct contains the root of the Merkle tree and the proof for a given identity. +/// +/// # Fields +/// * `root` - The root of the Merkle tree +/// * `proof` - The proof for the given identity +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct InclusionProof { + /// The root of the Merkle tree + pub root: Field, + /// The proof for the given identity + pub proof: PoseidonTreeProof, +} + +/// Errors that can occur when interacting with RPC operations. +#[crate::bedrock_error] +#[derive(Debug, Deserialize)] +pub enum WorldIdError { + /// Identity has not been initialized + #[error("WorldID identity not initialized. Call set_world_id_identity() first.")] + WorldIdIdentityNotInitialized, + /// Failed to fetch inclusion proof from sequencer + #[error("Inclusion proof error: {0}")] + InclusionProofError(String), + /// User has no more PBH transactions remaining + #[error("No PBH transactions remaining")] + NoPBHTransactionsRemaining, + /// Invalid network for World ID + #[error("Invalid network for World ID: {0}")] + InvalidNetworkError(String), + /// Proof error + #[error("Proof error: {0}")] + ProofError(#[from] ProofError), + /// RPC error + #[error("RPC error: {0}")] + RpcError(#[from] RpcError), +} + +/// Global World ID identity instance for Bedrock operations +static WORLD_ID_IDENTITY_INSTANCE: OnceLock> = OnceLock::new(); + +/// Sets the World ID identity. +/// +/// This function sets the World ID identity for Bedrock operations. +/// +/// # Arguments +/// * `identity` - The World ID identity to set +/// +/// # Returns +/// true if the World ID identity was set successfully, false otherwise. +/// +/// # Errors +/// This function will return false if the World ID identity is already initialized. +pub fn set_world_id_identity(identity: Arc) { + if WORLD_ID_IDENTITY_INSTANCE.set(identity).is_err() { + crate::warn!("World ID identity already initialized, ignoring"); + } else { + crate::info!("World ID identity initialized successfully"); + } +} + +/// Gets the World ID identity. +/// +/// # Returns +/// The World ID identity if it has been initialized, None otherwise. +pub fn get_world_id_identity() -> Option> { + WORLD_ID_IDENTITY_INSTANCE.get().cloned() +} + +/// Checks if the World ID identity has been initialized. +/// +/// # Returns +/// true if the World ID identity has been initialized, false otherwise. +pub fn is_world_id_identity_initialized() -> bool { + WORLD_ID_IDENTITY_INSTANCE.get().is_some() +} + +/// Generates a PBH proof for a given user operation. +/// # Arguments +/// - `user_op`: The user operation to generate the PBH proof for. +/// - `network`: The network to generate the PBH proof for. +/// # Errors +/// - Will throw a `WorldIdError` if the identity is not initialized. +/// - Will throw a `WorldIdError` if the network is invalid. +/// - Will throw a `WorldIdError` if the RPC client is not initialized. +/// - Will throw a `WorldIdError` if the inclusion proof fails. +/// - Will throw a `WorldIdError` if the unable to find a unused nullifier hash. +pub async fn generate_pbh_proof( + user_op: UserOperation, + network: Network, +) -> Result { + let packed_user_op: PackedUserOperation = PackedUserOperation::from(user_op); + let signal = hash_user_op(&packed_user_op); + let external_nullifier = find_unused_nullifier_hash(network).await?; + let encoded_external_nullifier = EncodedExternalNullifier::from(external_nullifier); + let identity = + get_world_id_identity().ok_or(WorldIdError::WorldIdIdentityNotInitialized)?; + + let inclusion_proof = fetch_inclusion_proof( + match network { + Network::WorldChain => PRODUCTION_SEQUENCER_URL, + Network::WorldChainSepolia => STAGING_SEQUENCER_URL, + _ => return Err(WorldIdError::InvalidNetworkError(network.to_string())), + }, + (*identity).clone(), + ) + .await + .map_err(|e| { + WorldIdError::InclusionProofError(format!( + "Failed to fetch inclusion proof: {e}" + )) + })?; + + let proof: SemaphoreProof = generate_proof( + &identity, + &inclusion_proof.proof, + encoded_external_nullifier.0, + signal, + )?; + + let nullifier_hash = + generate_nullifier_hash(&identity, encoded_external_nullifier.0); + + let proof = WorldchainBuilderProof(proof); + + Ok(WorldchainBuilderPBHPayload { + external_nullifier, + nullifier_hash, + root: inclusion_proof.root, + proof, + }) +} + +/// Finds the first unused nullifier hash for the current World ID identity in batches +/// # Arguments +/// - `network`: The network to find the unused nullifier hash on. +/// # Errors +/// - Will throw a `WorldIdError` if the identity is not initialized. +/// - Will throw a `WorldIdError` if the RPC client is not initialized. +/// - Will throw a `WorldIdError` if the network is invalid. +pub async fn find_unused_nullifier_hash( + network: Network, +) -> Result { + let identity = + get_world_id_identity().ok_or(WorldIdError::WorldIdIdentityNotInitialized)?; + + let rpc_client: &'static crate::transaction::RpcClient = get_rpc_client() + .map_err(|_| WorldIdError::RpcError(RpcError::HttpClientNotInitialized))?; + + let now = Utc::now(); + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let current_year = now.year() as u16; + #[allow(clippy::cast_possible_truncation)] + let current_month = now.month() as u16; + + let max_nonce = match network { + Network::WorldChain => PRODUCTION_MAX_NONCE, + Network::WorldChainSepolia => STAGING_MAX_NONCE, + _ => return Err(WorldIdError::InvalidNetworkError(network.to_string())), + }; + + // Process nonces in batches + for batch_start in (0..max_nonce).step_by(MAX_NONCE_BATCH_SIZE as usize) { + let batch_end = std::cmp::min(batch_start + MAX_NONCE_BATCH_SIZE, max_nonce); + let mut batch_hashes = Vec::new(); + let mut batch_external_nullifiers = Vec::new(); + + // Generate a batch of nullifier hashes + for nonce in batch_start..batch_end { + #[allow(clippy::cast_possible_truncation)] + let external_nullifier = + ExternalNullifier::v1(current_month as u8, current_year, nonce); + let encoded_external_nullifier = + EncodedExternalNullifier::from(external_nullifier); + + let nullifier_hash = + generate_nullifier_hash(&identity, encoded_external_nullifier.0); + + batch_hashes.push(U256::from_be_bytes(nullifier_hash.to_be_bytes::<32>())); + batch_external_nullifiers.push(external_nullifier); + } + + // Call contract with batch of hashes + let call = IPBHEntryPoint::getFirstUnspentNullifierHashCall { + hashes: batch_hashes, + }; + + // Try the RPC call, but continue to next batch if this one fails + let result = match rpc_client + .eth_call( + network, + *PBH_ENTRYPOINT_4337, + Bytes::from(call.abi_encode()), + ) + .await + { + Ok(result) => result, + Err(e) => { + crate::warn!("Failed to fetch first unused nullifier hash for batch. Continuing to next batch. {e}"); + continue; + } + }; + + let unsigned_value = U256::from_be_slice(&result); + let signed_from_slice = I256::from_raw(unsigned_value); + + // If result is not -1, we found an unused nullifier hash + if signed_from_slice != I256::MINUS_ONE { + let index = unsigned_value.to::(); + #[allow(clippy::cast_possible_truncation)] + let actual_nonce = batch_start + index as u16; + crate::info!("Found unused nullifier! Month: {current_month:?}, Year: {current_year:?}, Nonce: {actual_nonce:?}"); + // Return the external nullifier for the found index + return Ok(batch_external_nullifiers[index]); + } + } + + Err(WorldIdError::NoPBHTransactionsRemaining) +} + +/// Fetches an inclusion proof for a given identity from the signup sequencer. +/// +/// This function sends a request to the sequencer to fetch the inclusion proof for a given identity. +/// +/// # Arguments +/// * `url` - The URL of the sequencer +/// * `identity` - The identity to fetch the proof for +/// +/// # Errors +/// Returns `WorldIdError::InclusionProofError` if the request fails or response cannot be parsed. +pub async fn fetch_inclusion_proof( + url: &str, + identity: Identity, +) -> Result { + let client = Client::new(); + let commitment = identity.commitment(); + + // Make the HTTP request and map all errors to WorldIdError::InclusionProofError + let response = client + .post(format!("{url}/inclusionProof")) + .json(&serde_json::json! {{ + "identityCommitment": commitment, + }}) + .send() + .await + .map_err(|e| { + WorldIdError::InclusionProofError(format!("HTTP request failed: {e}")) + })? + .error_for_status() + .map_err(|e| { + WorldIdError::InclusionProofError(format!("HTTP status error: {e}")) + })?; + + // Parse the JSON response and map parsing errors + let proof: InclusionProof = response.json().await.map_err(|e| { + WorldIdError::InclusionProofError(format!("Failed to parse response: {e}")) + })?; + + Ok(proof) +} + +/// Computes a ZK-friendly hash of a `PackedUserOperation`. +/// +/// This function extracts key fields (sender, nonce, callData) from a `PackedUserOperation`, +/// encodes them using ABI packed encoding, and converts the result to a Field element +/// suitable for use in zero-knowledge proof circuits. +/// +/// # Arguments +/// * `user_op` - The `PackedUserOperation` to hash +/// +/// # Returns +/// A Field element representing the hash of the user operation +pub fn hash_user_op(user_op: &PackedUserOperation) -> Field { + let hash = SolValue::abi_encode_packed(&( + &user_op.sender, + &user_op.nonce, + &user_op.callData, + )); + hash_to_field(hash.as_slice()) +} diff --git a/bedrock/src/root_key/mod.rs b/bedrock/src/root_key/mod.rs index 5f45b3af..72ab0f14 100644 --- a/bedrock/src/root_key/mod.rs +++ b/bedrock/src/root_key/mod.rs @@ -1,5 +1,5 @@ use bedrock_macros::{bedrock_error, bedrock_export}; -use rand::{rngs::OsRng, RngCore}; +use rand::{rngs::OsRng, TryRngCore}; use secrecy::{ExposeSecret, SecretBox}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use subtle::ConstantTimeEq; diff --git a/bedrock/src/smart_account/nonce.rs b/bedrock/src/smart_account/nonce.rs index 0f1df329..cb588175 100644 --- a/bedrock/src/smart_account/nonce.rs +++ b/bedrock/src/smart_account/nonce.rs @@ -10,7 +10,7 @@ use ruint::aliases::U256; -use crate::primitives::BEDROCK_NONCE_PREFIX_CONST; +use crate::primitives::{BEDROCK_NONCE_PREFIX_CONST, PBH_NONCE_PREFIX_CONST}; /// Stable, never-reordered identifiers for transaction classes. #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -51,6 +51,8 @@ pub enum InstructionFlag { /// Follows 4337 specs: #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct NonceKeyV1 { + /// Whether the nonce is for a PBH transaction. + pub pbh: bool, /// Stable transaction class id. pub type_id: TransactionTypeId, /// Instruction flags bitfield. @@ -67,6 +69,7 @@ impl NonceKeyV1 { /// Builds a new v1 nonceKey with a random 7-byte tail. #[must_use] pub fn new( + pbh: bool, type_id: TransactionTypeId, instruction: InstructionFlag, metadata: [u8; 10], @@ -77,6 +80,7 @@ impl NonceKeyV1 { let mut tail = [0u8; 7]; tail.copy_from_slice(&bytes[1..8]); Self { + pbh, type_id, instruction, metadata, @@ -88,12 +92,14 @@ impl NonceKeyV1 { /// Test/advanced constructor allowing explicit random tail specification. #[must_use] pub const fn with_random_tail( + pbh: bool, type_id: TransactionTypeId, instruction: InstructionFlag, metadata: [u8; 10], random_tail: [u8; 7], ) -> Self { Self { + pbh, type_id, instruction, metadata, @@ -107,7 +113,11 @@ impl NonceKeyV1 { fn as_bytes(&self) -> [u8; 24] { let mut out: [u8; 24] = [0u8; 24]; // [0..=4] magic - out[0..=4].copy_from_slice(BEDROCK_NONCE_PREFIX_CONST); + if self.pbh { + out[0..=4].copy_from_slice(PBH_NONCE_PREFIX_CONST); + } else { + out[0..=4].copy_from_slice(BEDROCK_NONCE_PREFIX_CONST); + } // [5] typeId out[5] = self.type_id.as_u8(); // [6] instruction flags @@ -139,6 +149,7 @@ mod tests { let metadata = [0x11u8; 10]; let random_tail = [0x22u8; 7]; let key = NonceKeyV1::with_random_tail( + false, TransactionTypeId::Transfer, InstructionFlag::Default, metadata, @@ -161,6 +172,7 @@ mod tests { #[test] fn test_encode_nonce_sequence_is_zero() { let key = NonceKeyV1::with_random_tail( + false, TransactionTypeId::Transfer, InstructionFlag::Default, [0u8; 10], diff --git a/bedrock/src/smart_account/transaction_4337.rs b/bedrock/src/smart_account/transaction_4337.rs index 96e0afe7..4d5c8977 100644 --- a/bedrock/src/smart_account/transaction_4337.rs +++ b/bedrock/src/smart_account/transaction_4337.rs @@ -3,16 +3,25 @@ //! A transaction can be initialized through a `UserOperation` struct. //! -use crate::primitives::contracts::{EncodedSafeOpStruct, UserOperation}; +use crate::primitives::contracts::{ + EncodedSafeOpStruct, IPBHEntryPoint::PBHPayload, UserOperation, ENTRYPOINT_4337, +}; + +use crate::primitives::contracts::{ + PBH_ENTRYPOINT_4337, PBH_SAFE_4337_MODULE_MAINNET, PBH_SAFE_4337_MODULE_SEPOLIA, + PBH_SIGNATURE_AGGREGATOR_MAINNET, PBH_SIGNATURE_AGGREGATOR_SEPOLIA, +}; +use crate::primitives::world_id::generate_pbh_proof; use crate::primitives::{Network, PrimitiveError}; -use crate::smart_account::{SafeSmartAccount, SafeSmartAccountSigner}; +use crate::smart_account::{ + SafeSmartAccount, SafeSmartAccountSigner, GNOSIS_SAFE_4337_MODULE, +}; use crate::transaction::rpc::{RpcError, RpcProviderName}; use alloy::primitives::{aliases::U48, Address, Bytes, FixedBytes}; +use alloy::sol_types::SolValue; use chrono::{Duration, Utc}; -use crate::primitives::contracts::{ENTRYPOINT_4337, GNOSIS_SAFE_4337_MODULE}; - /// The default validity duration for 4337 `UserOperation` signatures. /// /// Operations are valid for this duration from the time they are signed. @@ -43,6 +52,7 @@ pub trait Is4337Encodable { &self, wallet_address: Address, metadata: Option, + pbh: bool, ) -> Result; /// Signs and executes a 4337 `UserOperation` by: @@ -67,21 +77,31 @@ pub trait Is4337Encodable { network: Network, self_sponsor_token: Option
, metadata: Option, + pbh: bool, provider: RpcProviderName, ) -> Result, RpcError> { // 0. Get the global RPC client let rpc_client = crate::transaction::rpc::get_rpc_client()?; // 1. Create preflight UserOperation using default metadata for this implementation - let mut user_operation = - self.as_preflight_user_operation(safe_account.wallet_address, metadata)?; + let mut user_operation = self.as_preflight_user_operation( + safe_account.wallet_address, + metadata, + pbh, + )?; + + let entrypoint = if pbh { + *PBH_ENTRYPOINT_4337 + } else { + *ENTRYPOINT_4337 + }; // 2. Request sponsorship let sponsor_response = rpc_client .sponsor_user_operation( network, &user_operation, - *ENTRYPOINT_4337, + entrypoint, self_sponsor_token, provider, ) @@ -93,6 +113,7 @@ pub trait Is4337Encodable { // 4. Compute validity timestamps // validAfter = 0 (immediately valid) let valid_after_u48 = U48::from(0u64); + // TODO: Set real value here? let valid_after_bytes: [u8; 6] = [0u8; 6]; // Set validUntil to the configured duration from now @@ -111,23 +132,72 @@ pub trait Is4337Encodable { valid_until_u48, )?; + let domain_separator: Address; + let mut aggregator: Option
= None; + + if pbh { + match network { + Network::WorldChain => { + domain_separator = *PBH_SAFE_4337_MODULE_MAINNET; + aggregator = Some(*PBH_SIGNATURE_AGGREGATOR_MAINNET); + } + Network::WorldChainSepolia => { + domain_separator = *PBH_SAFE_4337_MODULE_SEPOLIA; + aggregator = Some(*PBH_SIGNATURE_AGGREGATOR_SEPOLIA); + } + _ => { + return Err(RpcError::InvalidRequest(format!( + "Invalid network {network:?} for PBH" + ))) + } + } + } else { + domain_separator = *GNOSIS_SAFE_4337_MODULE; + } + let signature = safe_account.sign_digest( encoded_safe_op.into_transaction_hash(), network as u32, - Some(*GNOSIS_SAFE_4337_MODULE), + Some(domain_separator), )?; // Compose the final signature once (timestamps + actual 65-byte signature) - let mut full_signature = Vec::with_capacity(77); + let mut full_signature = Vec::new(); full_signature.extend_from_slice(&valid_after_bytes); full_signature.extend_from_slice(valid_until_bytes); full_signature.extend_from_slice(&signature.as_bytes()[..]); + // PBH Logic + if pbh { + let pbh_payload = generate_pbh_proof(user_operation.clone(), network).await; + match pbh_payload { + Ok(pbh_payload) => { + full_signature.extend_from_slice( + PBHPayload::from(pbh_payload).abi_encode().as_ref(), + ); + } + Err(e) => { + // TODO: Send standard user operation if PBH logic fails at any point + return Err(RpcError::InvalidRequest(format!( + "Failed to generate PBH payload {e}" + ))); + } + } + } + user_operation.signature = full_signature.into(); // 5. Submit UserOperation - let user_op_hash = rpc_client - .send_user_operation(network, &user_operation, *ENTRYPOINT_4337, provider) + let user_op_hash: FixedBytes<32> = rpc_client + // Always send to standard 4337 entrypoint even for PBH + // The bundler will route it to the PBH entrypoint if it's a PBH transaction + .send_user_operation( + network, + &user_operation, + *ENTRYPOINT_4337, + provider, + aggregator, + ) .await?; Ok(user_op_hash) diff --git a/bedrock/src/transaction/contracts/erc20.rs b/bedrock/src/transaction/contracts/erc20.rs index e564ea83..f36dd0e1 100644 --- a/bedrock/src/transaction/contracts/erc20.rs +++ b/bedrock/src/transaction/contracts/erc20.rs @@ -74,6 +74,7 @@ impl Is4337Encodable for Erc20 { &self, wallet_address: Address, metadata: Option, + pbh: bool, ) -> Result { let call_data = self.as_execute_user_op_call_data(); @@ -84,7 +85,8 @@ impl Is4337Encodable for Erc20 { } } - let key = NonceKeyV1::new( + let key: NonceKeyV1 = NonceKeyV1::new( + pbh, TransactionTypeId::Transfer, InstructionFlag::Default, metadata_bytes, @@ -134,7 +136,9 @@ mod tests { let wallet = Address::from_str("0x4564420674EA68fcc61b463C0494807C759d47e6").unwrap(); - let user_op = erc20.as_preflight_user_operation(wallet, None).unwrap(); + let user_op = erc20 + .as_preflight_user_operation(wallet, None, false) + .unwrap(); // Check nonce layout let be: [u8; 32] = user_op.nonce.to_be_bytes(); @@ -165,7 +169,7 @@ mod tests { }; let user_op = erc20 - .as_preflight_user_operation(wallet, Some(metadata)) + .as_preflight_user_operation(wallet, Some(metadata), false) .unwrap(); // Check nonce layout diff --git a/bedrock/src/transaction/mod.rs b/bedrock/src/transaction/mod.rs index c9aa97c1..ca69eb14 100644 --- a/bedrock/src/transaction/mod.rs +++ b/bedrock/src/transaction/mod.rs @@ -24,47 +24,26 @@ pub enum TransactionError { /// Extensions to `SafeSmartAccount` to enable high-level APIs for transactions. #[bedrock_export] impl SafeSmartAccount { - /// Allows executing an ERC-20 token transfer **on World Chain**. + /// Allows executing an ERC-20 token transfer /// /// # Arguments + /// - `network`: The network to transfer the tokens on. /// - `token_address`: The address of the ERC-20 token to transfer. /// - `to_address`: The address of the recipient. /// - `amount`: The amount of tokens to transfer as a stringified integer with the decimals of the token (e.g. 18 for USDC or WLD) + /// - `pbh`: Whether to use PBH. /// - `transfer_association`: Metadata value. The association of the transfer. - /// - /// # Example - /// - /// ```rust,no_run - /// use bedrock::smart_account::SafeSmartAccount; - /// use bedrock::transaction::TransactionError; - /// use bedrock::primitives::Network; - /// - /// # async fn example() -> Result<(), TransactionError> { - /// // Assume we have a configured SafeSmartAccount - /// # let safe_account = SafeSmartAccount::new("test_key".to_string(), "0x1234567890123456789012345678901234567890").unwrap(); - /// - /// // Transfer USDC on World Chain - /// let tx_hash = safe_account.transaction_transfer( - /// "0x79A02482A880BCE3F13E09Da970dC34DB4cD24d1", // USDC on World Chain - /// "0x1234567890123456789012345678901234567890", - /// "1000000", // 1 USDC (6 decimals) - /// None, - /// ).await?; - /// - /// println!("Transaction hash: {}", tx_hash.to_hex_string()); - /// # Ok(()) - /// # } - /// ``` - /// /// # Errors /// - Will throw a parsing error if any of the provided attributes are invalid. /// - Will throw an RPC error if the transaction submission fails. /// - Will throw an error if the global HTTP client has not been initialized. pub async fn transaction_transfer( &self, + network: Network, token_address: &str, to_address: &str, amount: &str, + pbh: bool, transfer_association: Option, ) -> Result { let token_address = Address::parse_from_ffi(token_address, "token_address")?; @@ -81,7 +60,7 @@ impl SafeSmartAccount { let provider = RpcProviderName::Alchemy; let user_op_hash = transaction - .sign_and_execute(self, Network::WorldChain, None, Some(metadata), provider) + .sign_and_execute(self, network, None, Some(metadata), pbh, provider) .await .map_err(|e| TransactionError::Generic { message: format!("Failed to execute transaction: {e}"), diff --git a/bedrock/src/transaction/rpc.rs b/bedrock/src/transaction/rpc.rs index 6f8749ba..754b4a6f 100644 --- a/bedrock/src/transaction/rpc.rs +++ b/bedrock/src/transaction/rpc.rs @@ -7,6 +7,7 @@ use crate::{ primitives::http_client::{get_http_client, HttpHeader}, primitives::{ + contracts::{IEntryPoint::PackedUserOperation, RpcUserOperationV0_7}, AuthenticatedHttpClient, HttpError, HttpMethod, Network, PrimitiveError, }, smart_account::{SafeSmartAccountError, UserOperation}, @@ -14,7 +15,7 @@ use crate::{ use alloy::hex::FromHex; use alloy::primitives::{Address, Bytes, FixedBytes, U128, U256}; use serde::{Deserialize, Serialize}; -use serde_json::Value; +use serde_json::{Map, Value}; use std::sync::{Arc, OnceLock}; /// Global RPC client instance for Bedrock operations @@ -39,6 +40,9 @@ pub enum RpcMethod { /// Submit a signed `UserOperation` #[serde(rename = "eth_sendUserOperation")] SendUserOperation, + /// Make a generic RPC `eth_call` to read data from a contract + #[serde(rename = "eth_call")] + EthCall, } /// 4337 provider selection to be passed by native apps @@ -68,6 +72,7 @@ impl RpcMethod { match self { Self::SponsorUserOperation => "wa_sponsorUserOperation", Self::SendUserOperation => "eth_sendUserOperation", + Self::EthCall => "eth_call", } } } @@ -106,6 +111,7 @@ struct ErrorPayload { /// Errors that can occur when interacting with RPC operations. #[crate::bedrock_error] +#[derive(Debug, Deserialize)] pub enum RpcError { /// HTTP request failed #[error("HTTP request failed: {0}")] @@ -142,6 +148,10 @@ pub enum RpcError { /// Safe Smart Account operation error #[error("Safe Smart Account operation failed: {0}")] SafeSmartAccountError(#[from] SafeSmartAccountError), + + /// Invalid inputs + #[error("Invalid request: {0}")] + InvalidRequest(String), } /// Response from `wa_sponsorUserOperation` @@ -189,6 +199,8 @@ impl RpcClient { format!("/v1/rpc/{}", network.network_name()) } + // async fn call_pbh_contract + /// Makes a generic RPC call with typed parameters and result, adding provider header /// /// # Arguments @@ -284,6 +296,7 @@ impl RpcClient { // Build params as a positional array. If no token is provided, omit the 3rd param entirely // so the backend can auto-fill an empty object as needed. let mut params: Vec = Vec::with_capacity(3); + // TODO: Should this be RPCUserOperationV0_7? params.push( serde_json::to_value(user_operation).map_err(|_| RpcError::JsonError)?, ); @@ -298,6 +311,13 @@ impl RpcClient { /// Submits a signed `UserOperation` via `eth_sendUserOperation` /// + /// # Arguments + /// - `network`: target network + /// - `user_operation`: the user operation to submit + /// - `entrypoint`: the entry point contract address + /// - `provider`: selected 4337 provider to include in headers + /// - `aggregator`: optional aggregator address to include in the user operation + /// /// # Errors /// /// Returns an error if: @@ -312,9 +332,24 @@ impl RpcClient { user_operation: &UserOperation, entrypoint: Address, provider: RpcProviderName, + aggregator: Option
, ) -> Result, RpcError> { + let packed_user_op: PackedUserOperation = user_operation.clone().into(); + + // Convert to RpcUserOperationV0_7 based on whether aggregator is provided + let rpc_user_op: RpcUserOperationV0_7 = if let Some(agg_addr) = aggregator { + (packed_user_op, agg_addr).into() + } else { + packed_user_op.into() + }; + + // Serialize the RpcUserOperationV0_7 to JSON + // Seralization will remove unused fields like factory and paymaster from JSON + let user_op_value = + serde_json::to_value(&rpc_user_op).map_err(|_| RpcError::JsonError)?; + let params = vec![ - serde_json::to_value(user_operation).map_err(|_| RpcError::JsonError)?, + user_op_value, serde_json::Value::String(format!("{entrypoint:?}")), ]; @@ -326,6 +361,49 @@ impl RpcClient { message: format!("Invalid userOpHash format: {e}"), }) } + + /// Makes a generic RPC call with typed parameters and result, adding provider header + /// + /// # Arguments + /// - `network`: target network + /// - `method`: JSON-RPC method to invoke + /// - `params`: JSON-RPC params (typed) + /// - `provider`: selected 4337 provider to include in headers + /// # Errors + /// - Will throw an RPC error if the RPC call fails. + pub async fn eth_call( + &self, + network: Network, + to: Address, + data: Bytes, + ) -> Result { + let params = vec![ + serde_json::Value::Object(Map::from_iter([ + ( + "to".to_string(), + serde_json::Value::String(format!("{to:?}")), + ), + ( + "data".to_string(), + serde_json::Value::String(format!("{data:?}")), + ), + ])), + serde_json::Value::String("latest".to_string()), // TODO: Allow passing in block number + ]; + + let result: String = self + .rpc_call( + network, + RpcMethod::EthCall, + params, + RpcProviderName::Alchemy, + ) + .await?; + + Bytes::from_hex(&result).map_err(|e| RpcError::InvalidResponse { + message: format!("Invalid eth_call result format: {e}"), + }) + } } /// Gets the global RPC client, initializing it on first access. diff --git a/bedrock/tests/common.rs b/bedrock/tests/common.rs index d7c624bd..2f0f8605 100644 --- a/bedrock/tests/common.rs +++ b/bedrock/tests/common.rs @@ -113,7 +113,7 @@ pub const SAFE_MODULE_SETUP_ADDRESS: Address = #[allow(dead_code)] // this is extensively used in Integration Tests pub fn setup_anvil() -> AnvilInstance { dotenvy::dotenv().ok(); - let rpc_url = std::env::var("WORLDCHAIN_RPC_URL").unwrap_or_else(|_| { + let rpc_url: String = std::env::var("WORLDCHAIN_RPC_URL").unwrap_or_else(|_| { // Fallback to a public, no-key RPC if available. "https://worldchain-mainnet.g.alchemy.com/v2/demo".to_string() }); diff --git a/bedrock/tests/test_smart_account_nonce.rs b/bedrock/tests/test_smart_account_nonce.rs index 50722b48..65f48b82 100644 --- a/bedrock/tests/test_smart_account_nonce.rs +++ b/bedrock/tests/test_smart_account_nonce.rs @@ -51,6 +51,7 @@ async fn test_rust_nonce_matches_solidity_encoding() -> anyhow::Result<()> { let metadata: [u8; 10] = [0x11; 10]; let random_tail: [u8; 7] = [0x22; 7]; let rust_nonce = NonceKeyV1::with_random_tail( + false, TransactionTypeId::Transfer, InstructionFlag::Default, metadata, diff --git a/bedrock/tests/test_smart_account_transfer.rs b/bedrock/tests/test_smart_account_transfer.rs index fdaf1f07..5f193ea9 100644 --- a/bedrock/tests/test_smart_account_transfer.rs +++ b/bedrock/tests/test_smart_account_transfer.rs @@ -9,8 +9,11 @@ use alloy::{ }; use bedrock::{ - primitives::http_client::{ - set_http_client, AuthenticatedHttpClient, HttpError, HttpHeader, HttpMethod, + primitives::{ + http_client::{ + set_http_client, AuthenticatedHttpClient, HttpError, HttpHeader, HttpMethod, + }, + Network, }, smart_account::{SafeSmartAccount, ENTRYPOINT_4337}, transaction::foreign::UnparsedUserOperation, @@ -234,7 +237,7 @@ where // ------------------ The test for the full transaction_transfer flow ------------------ #[tokio::test] -async fn test_transaction_transfer_full_flow_executes_user_operation( +async fn test_transaction_transfer_full_flow_executes_user_operation_non_pbh( ) -> anyhow::Result<()> { // 1) Spin up anvil fork let anvil = setup_anvil(); @@ -294,9 +297,11 @@ async fn test_transaction_transfer_full_flow_executes_user_operation( let amount = "1000000000000000000"; // 1 WLD let _user_op_hash = safe_account .transaction_transfer( + Network::WorldChain, &wld_token_address.to_string(), &recipient.to_string(), amount, + false, None, ) .await diff --git a/bedrock/tests/test_smart_pbh_sepolia.rs b/bedrock/tests/test_smart_pbh_sepolia.rs new file mode 100644 index 00000000..3b3104ed --- /dev/null +++ b/bedrock/tests/test_smart_pbh_sepolia.rs @@ -0,0 +1,190 @@ +use std::sync::Arc; + +use alloy::{ + network::Ethereum, + providers::{Provider, ProviderBuilder}, + signers::local::PrivateKeySigner, +}; +use reqwest::Url; + +use dotenvy::dotenv; + +use bedrock::{ + primitives::{ + http_client::{ + set_http_client, AuthenticatedHttpClient, HttpError, HttpHeader, HttpMethod, + }, + world_id::set_world_id_identity, + Network, + }, + smart_account::SafeSmartAccount, +}; + +use semaphore_rs::identity::Identity; +use serde::Serialize; +use serde_json::json; + +mod common; + +// ------------------ Mock HTTP client that actually executes the op on Anvil ------------------ +#[derive(Clone)] +struct AlchemyBackedHttpClient

+where + P: Provider + Clone + Send + Sync + 'static, +{ + provider: P, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct SponsorUserOperationResponseLite<'a> { + paymaster: &'a str, + paymaster_data: &'a str, + pre_verification_gas: String, + verification_gas_limit: String, + call_gas_limit: String, + paymaster_verification_gas_limit: String, + paymaster_post_op_gas_limit: String, + max_priority_fee_per_gas: String, + max_fee_per_gas: String, +} + +#[async_trait::async_trait] +impl

AuthenticatedHttpClient for AlchemyBackedHttpClient

+where + P: Provider + Clone + Send + Sync + 'static, +{ + async fn fetch_from_app_backend( + &self, + _url: String, + method: HttpMethod, + _headers: Vec, + body: Option>, + ) -> Result, HttpError> { + if method != HttpMethod::Post { + return Err(HttpError::Generic { + message: "unsupported method".into(), + }); + } + + let body = body.ok_or(HttpError::Generic { + message: "missing body".into(), + })?; + + let root: serde_json::Value = + serde_json::from_slice(&body).map_err(|_| HttpError::Generic { + message: "invalid json".into(), + })?; + + let method = root + .get("method") + .and_then(|m| m.as_str()) + .ok_or(HttpError::Generic { + message: "invalid json".into(), + })? + .to_string(); + let id = root.get("id").cloned().unwrap_or(serde_json::Value::Null); + let params = root + .get("params") + .cloned() + .unwrap_or(serde_json::Value::Null); + + match method.as_str() { + // Respond with minimal, sane gas values and no paymaster + "wa_sponsorUserOperation" => { + let result = SponsorUserOperationResponseLite { + paymaster: "0x0000000000000000000000000000000000000000", + paymaster_data: "0x", + pre_verification_gas: "0x20000".into(), + verification_gas_limit: "0x20000".into(), + call_gas_limit: "0x20000".into(), + paymaster_verification_gas_limit: "0x0".into(), + paymaster_post_op_gas_limit: "0x0".into(), + max_priority_fee_per_gas: "0x3b9aca00".into(), // 1 gwei + max_fee_per_gas: "0x3b9aca00".into(), // 1 gwei + }; + let resp = json!({ + "jsonrpc": "2.0", + "id": id, + "result": result, + }); + Ok(serde_json::to_vec(&resp).unwrap()) + } + // Forward all other methods to the actual provider + _ => { + // Forward the JSON-RPC request to the provider + let response = self + .provider + .raw_request::( + method.into(), + params, + ) + .await + .map_err(|e| HttpError::Generic { + message: format!("Provider request failed: {e}"), + })?; + + let resp = json!({ + "jsonrpc": "2.0", + "id": id, + "result": response, + }); + Ok(serde_json::to_vec(&resp).unwrap()) + } + } + } +} + +// ------------------ The test for the full transaction_transfer flow ------------------ + +#[tokio::test] +async fn test_pbh_transaction_transfer_full_flow() -> anyhow::Result<()> { + dotenv().ok(); + + let rpc_url: Url = std::env::var("WORLDCHAIN_RPC_URL_SEPOLIA") + .unwrap() + .parse()?; + let nullifier = std::env::var("TESTNET_NULLIFIER").unwrap(); + let trapdoor = std::env::var("TESTNET_TRAPDOOR").unwrap(); + let private_key = std::env::var("TESTNET_PRIVATE_KEY").unwrap(); + let safe_address = std::env::var("TESTNET_SAFE_ADDRESS").unwrap(); + + let owner_signer = PrivateKeySigner::from_slice(&hex::decode(private_key)?)?; + + let owner_key_hex = hex::encode(owner_signer.to_bytes()); + + let provider = ProviderBuilder::new() + .wallet(owner_signer.clone()) + .connect_http(rpc_url); + + // 7) HTTP client that routes calls to Alchemy + let client = AlchemyBackedHttpClient { + provider: provider.clone(), + }; + let _ = set_http_client(Arc::new(client)); + + let identity = Identity { + nullifier: nullifier.parse().unwrap(), + trapdoor: trapdoor.parse().unwrap(), + }; + set_world_id_identity(Arc::new(identity)); + + // 8) Execute high-level transfer via transaction_transfer + let safe_account = SafeSmartAccount::new(owner_key_hex, safe_address.as_str())?; + let amount = "1"; + let recipient = safe_address; + + let _user_op_hash = safe_account + .transaction_transfer( + Network::WorldChainSepolia, + "0xC82Ea35634BcE95C394B6BC00626f827bB0F4801", // WORLD SEPOLIA LINK TOKEN + recipient.as_str(), + amount, + true, + None, + ) + .await + .expect("transaction_transfer failed"); + + Ok(()) +}