diff --git a/.github/workflows/nextest.yml b/.github/workflows/nextest.yml index 880354080..da862c657 100644 --- a/.github/workflows/nextest.yml +++ b/.github/workflows/nextest.yml @@ -67,12 +67,10 @@ jobs: with: bun-version: latest - name: Setup Python - if: contains(matrix.name, 'external') uses: actions/setup-python@v4 with: python-version: 3.11 - name: Install Vyper - if: contains(matrix.name, 'external') run: pip install vyper~=0.4.0 - name: Forge RPC cache diff --git a/Cargo.lock b/Cargo.lock index 8563f8af6..b95f61895 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,9 +96,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-chains" -version = "0.1.38" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "156bfc5dcd52ef9a5f33381701fa03310317e14c65093a9430d3e3557b08dcd3" +checksum = "836cf02383d9ebb35502d379bcd1ae803155094077eaab9c29131d888cd5fa3e" dependencies = [ "alloy-primitives", "num_enum 0.7.3", @@ -108,8 +108,8 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-eips", "alloy-primitives", @@ -123,8 +123,8 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -143,9 +143,9 @@ dependencies = [ [[package]] name = "alloy-dyn-abi" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6228abfc751a29cde117b0879b805a3e0b3b641358f063272c83ca459a56886" +checksum = "f5228b189b18b85761340dc9eaac0141148a8503657b36f9bc3a869413d987ca" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -177,13 +177,14 @@ dependencies = [ [[package]] name = "alloy-eip7702" -version = "0.1.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" +checksum = "64ffc577390ce50234e02d841214b3dc0bea6aaaae8e04bbf3cb82e9a45da9eb" dependencies = [ "alloy-primitives", "alloy-rlp", "arbitrary", + "derive_more 1.0.0", "k256 0.13.4", "rand 0.8.5", "serde", @@ -191,8 +192,8 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -208,8 +209,8 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-primitives", "alloy-serde", @@ -218,9 +219,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d46eb5871592c216d39192499c95a99f7175cb94104f88c307e6dc960676d9f1" +checksum = "31a0f0d51db8a1a30a4d98a9f90e090a94c8f44cb4d9eafc7e03aa6d00aae984" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -230,8 +231,8 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -243,8 +244,8 @@ dependencies = [ [[package]] name = "alloy-network" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -263,8 +264,8 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -275,9 +276,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f35429a652765189c1c5092870d8360ee7b7769b09b06d89ebaefd34676446" +checksum = "8edae627382349b56cd6a7a2106f4fd69b243a9233e560c55c2e03cabb7e1d3c" dependencies = [ "alloy-rlp", "arbitrary", @@ -307,8 +308,8 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-chains", "alloy-consensus", @@ -333,20 +334,23 @@ dependencies = [ "futures 0.3.31", "futures-utils-wasm", "lru", - "pin-project 1.1.6", - "reqwest 0.12.8", + "parking_lot 0.12.3", + "pin-project 1.1.7", + "reqwest 0.12.9", + "schnellru", "serde", "serde_json", "thiserror", "tokio", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-pubsub" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -363,9 +367,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" +checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f" dependencies = [ "alloy-rlp-derive", "arrayvec 0.7.6", @@ -374,19 +378,19 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" +checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "alloy-rpc-client" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -396,8 +400,8 @@ dependencies = [ "alloy-transport-ipc", "alloy-transport-ws", "futures 0.3.31", - "pin-project 1.1.6", - "reqwest 0.12.8", + "pin-project 1.1.7", + "reqwest 0.12.9", "serde", "serde_json", "tokio", @@ -405,12 +409,13 @@ dependencies = [ "tower 0.5.1", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-rpc-types" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-primitives", "alloy-rpc-types-anvil", @@ -424,8 +429,8 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-primitives", "alloy-serde", @@ -434,8 +439,8 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -451,8 +456,8 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -469,8 +474,8 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -482,8 +487,8 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -493,8 +498,8 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-primitives", "serde", @@ -503,8 +508,8 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-dyn-abi", "alloy-primitives", @@ -518,8 +523,8 @@ dependencies = [ [[package]] name = "alloy-signer-aws" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-consensus", "alloy-network", @@ -535,8 +540,8 @@ dependencies = [ [[package]] name = "alloy-signer-gcp" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-consensus", "alloy-network", @@ -552,8 +557,8 @@ dependencies = [ [[package]] name = "alloy-signer-ledger" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -571,8 +576,8 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-consensus", "alloy-network", @@ -589,8 +594,8 @@ dependencies = [ [[package]] name = "alloy-signer-trezor" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-consensus", "alloy-network", @@ -605,23 +610,23 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2395336745358cc47207442127c47c63801a7065ecc0aa928da844f8bb5576" +checksum = "841eabaa4710f719fddbc24c95d386eae313f07e6da4babc25830ee37945be0c" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "alloy-sol-macro-expander" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed5047c9a241df94327879c2b0729155b58b941eae7805a7ada2e19436e6b39" +checksum = "6672337f19d837b9f7073c45853aeb528ed9f7dd6a4154ce683e9e5cb7794014" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", @@ -629,35 +634,35 @@ dependencies = [ "heck", "indexmap 2.6.0", "proc-macro-error2", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", "syn-solidity", "tiny-keccak 2.0.2", ] [[package]] name = "alloy-sol-macro-input" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dee02a81f529c415082235129f0df8b8e60aa1601b9c9298ffe54d75f57210b" +checksum = "0dff37dd20bfb118b777c96eda83b2067f4226d2644c5cfa00187b3bc01770ba" dependencies = [ "alloy-json-abi", "const-hex", "dunce", "heck", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "serde_json", - "syn 2.0.79", + "syn 2.0.87", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f631f0bd9a9d79619b27c91b6b1ab2c4ef4e606a65192369a1ee05d40dcf81cc" +checksum = "5b853d42292dbb159671a3edae3b2750277ff130f32b726fe07dc2b17aa6f2b5" dependencies = [ "serde", "winnow 0.6.20", @@ -665,9 +670,9 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2841af22d99e2c0f82a78fe107b6481be3dd20b89bfb067290092794734343a" +checksum = "aa828bb1b9a6dc52208fbb18084fb9ce2c30facc2bfda6a5d922349b4990354f" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -678,8 +683,8 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#21484592682f146ba8f50de0d90883a10e82d52f" dependencies = [ "alloy-json-rpc", "base64 0.22.1", @@ -692,16 +697,17 @@ dependencies = [ "tower 0.5.1", "tracing", "url", + "wasmtimer", ] [[package]] name = "alloy-transport-http" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#31bccc864525b5ba64fefb8211363807c7a43d2d" dependencies = [ "alloy-json-rpc", "alloy-transport", - "reqwest 0.12.8", + "reqwest 0.12.9", "serde_json", "tower 0.5.1", "tracing", @@ -710,8 +716,8 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#31bccc864525b5ba64fefb8211363807c7a43d2d" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -719,7 +725,7 @@ dependencies = [ "bytes", "futures 0.3.31", "interprocess", - "pin-project 1.1.6", + "pin-project 1.1.7", "serde", "serde_json", "tempfile", @@ -730,14 +736,14 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "0.4.2" -source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.4.2#36f6a2ef91341075338bddcfa14cfb5bd5203ef8" +version = "0.5.4" +source = "git+https://github.com/Karrq/alloy?branch=zksync-v0.5.4#31bccc864525b5ba64fefb8211363807c7a43d2d" dependencies = [ "alloy-pubsub", "alloy-transport", "futures 0.3.31", "http 1.1.0", - "rustls 0.23.15", + "rustls 0.23.16", "serde_json", "tokio", "tokio-tungstenite 0.24.0", @@ -799,9 +805,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" dependencies = [ "anstyle", "anstyle-parse", @@ -814,36 +820,36 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -936,6 +942,7 @@ dependencies = [ "revm", "serde", "serde_json", + "thiserror", ] [[package]] @@ -958,7 +965,7 @@ dependencies = [ "futures 0.3.31", "interprocess", "parking_lot 0.12.3", - "pin-project 1.1.6", + "pin-project 1.1.7", "serde", "serde_json", "thiserror", @@ -969,9 +976,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" [[package]] name = "arbitrary" @@ -1070,7 +1077,7 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint 0.4.6", "num-traits", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -1175,9 +1182,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "103db485efc3e41214fe4fda9f3dbeae2eb9082f48fd236e6095627a9422066e" +checksum = "0cb8f1d480b0ea3783ab015936d2a55c87e219676f0c0b7dec61494043f21857" dependencies = [ "flate2", "futures-core", @@ -1201,9 +1208,9 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1223,9 +1230,9 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1234,9 +1241,9 @@ version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1296,9 +1303,9 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1309,9 +1316,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-config" -version = "1.5.8" +version = "1.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7198e6f03240fdceba36656d8be440297b6b82270325908c7381f37d826a74f6" +checksum = "2d6448cfb224dd6a9b9ac734f58622dd0d4751f3589f3b777345745f46b2eb14" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1403,9 +1410,9 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.47.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564a597a3c71a957d60a2e4c62c93d78ee5a0d636531e15b760acad983a5c18e" +checksum = "1f4c89f1d2e0df99ccd21f98598c1e587ad78bd87ae22a74aba392b5566bb038" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1425,9 +1432,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.46.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc2faec3205d496c7e57eff685dd944203df7ce16a4116d0281c44021788a7b" +checksum = "ded855583fa1d22e88fe39fd6062b062376e50a8211989e07cf5e38d52eb3453" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1447,9 +1454,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.47.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c93c241f52bc5e0476e259c953234dab7e2a35ee207ee202e86c0095ec4951dc" +checksum = "9177ea1192e6601ae16c7273385690d88a7ed386a00b74a6bc894d12103cd933" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1469,9 +1476,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.46.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b259429be94a3459fa1b00c5684faee118d74f9577cc50aebadc36e507c63b5f" +checksum = "823ef553cf36713c97453e2ddff1eb8f62be7f4523544e2a5db64caf80100f0a" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1492,9 +1499,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.2.4" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8db6904450bafe7473c6ca9123f88cc11089e41a025408f992db4e22d3be68" +checksum = "5619742a0d8f253be760bfbb8e8e8368c69e3587e4637af5754e488a611499b1" dependencies = [ "aws-credential-types", "aws-smithy-http", @@ -1565,9 +1572,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.7.2" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a065c0fe6fdbdf9f11817eb68582b2ab4aff9e9c39e986ae48f7ec576c6322db" +checksum = "be28bd063fa91fd871d131fc8b68d7cd4c5fa0869bea68daca50dcb1cbd76be2" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -1609,9 +1616,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.7" +version = "1.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147100a7bea70fa20ef224a6bad700358305f5dc0f84649c53769761395b355b" +checksum = "07c9cdc179e6afbf5d391ab08c85eac817b51c87e1892a5edb5f7bbdc64314b4" dependencies = [ "base64-simd", "bytes", @@ -1719,7 +1726,7 @@ checksum = "d67782c3f868daa71d3533538e98a8e13713231969def7536e8039606fc46bf0" dependencies = [ "fastrand", "futures-core", - "pin-project 1.1.6", + "pin-project 1.1.7", "tokio", ] @@ -1852,12 +1859,12 @@ dependencies = [ "lazycell", "peeking_take_while", "prettyplease", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1874,12 +1881,12 @@ dependencies = [ "lazycell", "log", "prettyplease", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.79", + "syn 2.0.87", "which 4.4.2", ] @@ -2048,9 +2055,9 @@ checksum = "2a2af3eac944c12cdf4423eab70d310da0a8e5851a18ffb192c0a5e3f7ae1663" dependencies = [ "darling 0.20.10", "ident_case", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2102,9 +2109,9 @@ checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" dependencies = [ "once_cell", "proc-macro-crate 3.2.0", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", "syn_derive", ] @@ -2164,7 +2171,7 @@ version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -2189,9 +2196,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" dependencies = [ "serde", ] @@ -2364,9 +2371,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.30" +version = "1.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9" dependencies = [ "jobserver", "libc", @@ -2431,7 +2438,7 @@ dependencies = [ "foundry-config", "foundry-evm", "regex", - "reqwest 0.12.8", + "reqwest 0.12.9", "revm", "rustyline", "semver 1.0.23", @@ -2539,14 +2546,14 @@ dependencies = [ [[package]] name = "circuit_encodings" -version = "0.150.6" +version = "0.150.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5128d4b8fbb27ac453f573a95601058e74487bdafd22a3168cded66bf340c28" +checksum = "2501cc688ef391013019495ae7035cfd54f86987e36d10f73976ce4c5d413c5a" dependencies = [ "derivative", "serde", - "zk_evm 0.150.6", - "zkevm_circuits 0.150.6", + "zk_evm 0.150.7", + "zkevm_circuits 0.150.7", ] [[package]] @@ -2606,11 +2613,11 @@ dependencies = [ [[package]] name = "circuit_sequencer_api" -version = "0.150.6" +version = "0.150.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093d0c2c0b39144ddb4e1e88d73d95067ce34ec7750808b2eed01edbb510b88e" +checksum = "917d27db531fdd98a51e42ea465bc097f48cc849e7fad68d7856087d15125be1" dependencies = [ - "circuit_encodings 0.150.6", + "circuit_encodings 0.150.7", "derivative", "rayon", "serde", @@ -2655,9 +2662,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.33" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9646e2e245bf62f45d39a0f3f36f1171ad1ea0d6967fd114bca72cb02a8fcdfb" +checksum = "86bc73de94bc81e52f3bebec71bc4463e9748f7a59166663e32044669577b0e2" dependencies = [ "clap", ] @@ -2679,9 +2686,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2890,9 +2897,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" @@ -3018,7 +3025,7 @@ version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "unicode-xid 0.2.6", ] @@ -3244,7 +3251,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3288,9 +3295,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3321,7 +3328,7 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "strsim 0.10.0", "syn 1.0.109", @@ -3335,10 +3342,10 @@ checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "strsim 0.11.1", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3360,7 +3367,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3454,7 +3461,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -3465,9 +3472,9 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3486,9 +3493,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ "darling 0.20.10", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3498,7 +3505,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3508,10 +3515,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case 0.4.0", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "rustc_version 0.4.1", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3530,9 +3537,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "convert_case 0.6.0", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", "unicode-xid 0.2.6", ] @@ -3644,16 +3651,16 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "divan" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d567df2c9c2870a43f3f2bd65aaeb18dbce1c18f217c3e564b4fbaeb3ee56c" +checksum = "6e05d17bd4ff1c1e7998ed4623d2efd91f72f1e24141ac33aac9377974270e1f" dependencies = [ "cfg-if 1.0.0", "clap", @@ -3665,13 +3672,13 @@ dependencies = [ [[package]] name = "divan-macros" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27540baf49be0d484d8f0130d7d8da3011c32a44d4fc873368154f1510e574a2" +checksum = "1b4464d46ce68bfc7cb76389248c7c254def7baca8bece0693b02b83842c4c88" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3899,9 +3906,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" dependencies = [ "once_cell", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3910,9 +3917,9 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3968,8 +3975,8 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "era_test_node" -version = "0.1.0-alpha.29" -source = "git+https://github.com/matter-labs/era-test-node.git?rev=56c4e92693b5dd5ab166e368b066d9169b438855#56c4e92693b5dd5ab166e368b066d9169b438855" +version = "0.1.0-alpha.31" +source = "git+https://github.com/matter-labs/era-test-node.git?rev=94503847b402f0161c3372d5f357a4cb16a2d66d#94503847b402f0161c3372d5f357a4cb16a2d66d" dependencies = [ "anyhow", "bigdecimal 0.3.1", @@ -3999,8 +4006,6 @@ dependencies = [ "toml 0.8.19", "tracing", "tracing-subscriber", - "zkevm_opcode_defs 0.150.0", - "zksync_basic_types", "zksync_contracts", "zksync_multivm", "zksync_types", @@ -4197,7 +4202,7 @@ dependencies = [ "ethers-providers", "futures-util", "once_cell", - "pin-project 1.1.6", + "pin-project 1.1.7", "serde", "serde_json", "thiserror", @@ -4216,13 +4221,13 @@ dependencies = [ "ethers-etherscan", "eyre", "prettyplease", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "regex", "reqwest 0.11.27", "serde", "serde_json", - "syn 2.0.79", + "syn 2.0.87", "toml 0.8.19", "walkdir", ] @@ -4237,10 +4242,10 @@ dependencies = [ "const-hex", "ethers-contract-abigen", "ethers-core", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "serde_json", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -4266,7 +4271,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.79", + "syn 2.0.87", "tempfile", "thiserror", "tiny-keccak 2.0.2", @@ -4337,7 +4342,7 @@ dependencies = [ "instant", "jsonwebtoken 8.3.0", "once_cell", - "pin-project 1.1.6", + "pin-project 1.1.7", "reqwest 0.11.27", "serde", "serde_json", @@ -4685,6 +4690,7 @@ dependencies = [ "forge-doc", "forge-fmt", "forge-script", + "forge-script-sequence", "forge-sol-macro-gen", "forge-verify", "foundry-block-explorers", @@ -4716,7 +4722,7 @@ dependencies = [ "quick-junit", "rayon", "regex", - "reqwest 0.12.8", + "reqwest 0.12.9", "revm-inspectors", "semver 1.0.23", "serde", @@ -4847,6 +4853,7 @@ dependencies = [ "serde", "serde_json", "tracing", + "walkdir", ] [[package]] @@ -4859,10 +4866,10 @@ dependencies = [ "eyre", "foundry-common", "prettyplease", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "serde_json", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -4889,7 +4896,7 @@ dependencies = [ "futures 0.3.31", "itertools 0.13.0", "regex", - "reqwest 0.12.8", + "reqwest 0.12.9", "revm-primitives", "semver 1.0.23", "serde", @@ -4911,14 +4918,14 @@ dependencies = [ [[package]] name = "foundry-block-explorers" -version = "0.7.3" -source = "git+https://github.com/Moonsong-Labs/block-explorers?branch=zksync-v0.7.3#ef81bf5a733517de496ae1d14024ea9b4fcd4d3c" +version = "0.8.0" +source = "git+https://github.com/Moonsong-Labs/block-explorers?branch=zksync-v0.7.3#0cf56eaa2484e420ef38243773eff671c5f142a0" dependencies = [ "alloy-chains", "alloy-json-abi", "alloy-primitives", "foundry-compilers", - "reqwest 0.12.8", + "reqwest 0.12.9", "semver 1.0.23", "serde", "serde_json", @@ -4946,6 +4953,7 @@ dependencies = [ "dialoguer", "ecdsa 0.16.9", "eyre", + "forge-script-sequence", "foundry-cheatcodes-common", "foundry-cheatcodes-spec", "foundry-common", @@ -5003,9 +5011,11 @@ version = "0.0.2" dependencies = [ "alloy-chains", "alloy-dyn-abi", + "alloy-eips", "alloy-json-abi", "alloy-primitives", "alloy-provider", + "alloy-rlp", "alloy-transport", "clap", "color-eyre", @@ -5022,6 +5032,7 @@ dependencies = [ "indicatif", "regex", "serde", + "serde_json", "strsim 0.11.1", "strum", "tempfile", @@ -5053,6 +5064,8 @@ dependencies = [ "alloy-transport-http", "alloy-transport-ipc", "alloy-transport-ws", + "anstream", + "anstyle", "async-trait", "clap", "comfy-table", @@ -5065,11 +5078,12 @@ dependencies = [ "foundry-zksync-compiler", "globset", "num-format", - "reqwest 0.12.8", + "reqwest 0.12.9", "semver 1.0.23", "serde", "serde_json", "similar-asserts", + "terminal_size", "thiserror", "tokio", "tower 0.4.13", @@ -5085,6 +5099,7 @@ version = "0.0.2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", + "alloy-network", "alloy-primitives", "alloy-rpc-types", "alloy-serde", @@ -5100,8 +5115,8 @@ dependencies = [ [[package]] name = "foundry-compilers" -version = "0.11.4" -source = "git+https://github.com/Moonsong-Labs/compilers?branch=zksync-v0.11.4#7d2dc971a21db4e188fd42d086ad0daea2dc7ae9" +version = "0.11.6" +source = "git+https://github.com/Moonsong-Labs/compilers?branch=zksync-v0.11.6#7c69695e5c75451f158dd2456bf8c94a7492ea0b" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -5121,7 +5136,7 @@ dependencies = [ "path-slash", "rand 0.8.5", "rayon", - "reqwest 0.12.8", + "reqwest 0.12.9", "semver 1.0.23", "serde", "serde_json", @@ -5140,8 +5155,8 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts" -version = "0.11.4" -source = "git+https://github.com/Moonsong-Labs/compilers?branch=zksync-v0.11.4#7d2dc971a21db4e188fd42d086ad0daea2dc7ae9" +version = "0.11.6" +source = "git+https://github.com/Moonsong-Labs/compilers?branch=zksync-v0.11.6#7c69695e5c75451f158dd2456bf8c94a7492ea0b" dependencies = [ "foundry-compilers-artifacts-solc", "foundry-compilers-artifacts-vyper", @@ -5150,8 +5165,8 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-solc" -version = "0.11.4" -source = "git+https://github.com/Moonsong-Labs/compilers?branch=zksync-v0.11.4#7d2dc971a21db4e188fd42d086ad0daea2dc7ae9" +version = "0.11.6" +source = "git+https://github.com/Moonsong-Labs/compilers?branch=zksync-v0.11.6#7c69695e5c75451f158dd2456bf8c94a7492ea0b" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -5173,8 +5188,8 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-vyper" -version = "0.11.4" -source = "git+https://github.com/Moonsong-Labs/compilers?branch=zksync-v0.11.4#7d2dc971a21db4e188fd42d086ad0daea2dc7ae9" +version = "0.11.6" +source = "git+https://github.com/Moonsong-Labs/compilers?branch=zksync-v0.11.6#7c69695e5c75451f158dd2456bf8c94a7492ea0b" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -5187,8 +5202,8 @@ dependencies = [ [[package]] name = "foundry-compilers-artifacts-zksolc" -version = "0.11.4" -source = "git+https://github.com/Moonsong-Labs/compilers?branch=zksync-v0.11.4#7d2dc971a21db4e188fd42d086ad0daea2dc7ae9" +version = "0.11.6" +source = "git+https://github.com/Moonsong-Labs/compilers?branch=zksync-v0.11.6#7c69695e5c75451f158dd2456bf8c94a7492ea0b" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -5208,8 +5223,8 @@ dependencies = [ [[package]] name = "foundry-compilers-core" -version = "0.11.4" -source = "git+https://github.com/Moonsong-Labs/compilers?branch=zksync-v0.11.4#7d2dc971a21db4e188fd42d086ad0daea2dc7ae9" +version = "0.11.6" +source = "git+https://github.com/Moonsong-Labs/compilers?branch=zksync-v0.11.6#7c69695e5c75451f158dd2456bf8c94a7492ea0b" dependencies = [ "alloy-primitives", "cfg-if 1.0.0", @@ -5247,7 +5262,7 @@ dependencies = [ "number_prefix", "path-slash", "regex", - "reqwest 0.12.8", + "reqwest 0.12.9", "revm-primitives", "semver 1.0.23", "serde", @@ -5306,6 +5321,7 @@ dependencies = [ "proptest", "revm", "revm-inspectors", + "serde", "thiserror", "tracing", ] @@ -5430,8 +5446,8 @@ dependencies = [ [[package]] name = "foundry-fork-db" -version = "0.4.0" -source = "git+https://github.com/Moonsong-Labs/foundry-zksync-fork-db?branch=zksync-v0.4.0#183df1a1865ff9af3cb8e3a1675e1bafe0bca69d" +version = "0.6.0" +source = "git+https://github.com/Moonsong-Labs/foundry-zksync-fork-db?branch=zksync-v0.6.0#f2e915d1c476007ae16be9fb96b25ffe1b8f5113" dependencies = [ "alloy-primitives", "alloy-provider", @@ -5465,9 +5481,9 @@ name = "foundry-macros" version = "0.0.2" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5782,9 +5798,9 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5858,7 +5874,7 @@ dependencies = [ "once_cell", "prost 0.13.3", "prost-types 0.13.3", - "reqwest 0.12.8", + "reqwest 0.12.9", "secret-vault-value", "serde", "serde_json", @@ -5962,9 +5978,9 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.14.8" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03f76169faa0dec598eac60f83d7fcdd739ec16596eca8fb144c88973dbe6f8c" +checksum = "f3de3fdca9c75fa4b83a76583d265fa49b1de6b088ebcd210749c24ceeb74660" dependencies = [ "bitflags 2.6.0", "bstr", @@ -5975,9 +5991,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c84b7af01e68daf7a6bb8bb909c1ff5edb3ce4326f1f43063a5a96d3c3c8a5" +checksum = "d10d543ac13c97292a15e8e8b7889cd006faf739777437ed95362504b8fe81a0" dependencies = [ "bstr", "itoa", @@ -6065,9 +6081,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.11" +version = "0.10.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebfc4febd088abdcbc9f1246896e57e37b7a34f6909840045a1767c6dafac7af" +checksum = "c04e5a94fdb56b1e91eb7df2658ad16832428b8eeda24ff1a0f0288de2bce554" dependencies = [ "bstr", "gix-trace", @@ -6099,9 +6115,9 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fe4d52f30a737bbece5276fab5d3a8b276dc2650df963e293d0673be34e7a5f" +checksum = "a2007538eda296445c07949cf04f4a767307d887184d6b3e83e2d636533ddc6e" dependencies = [ "bitflags 2.6.0", "gix-path", @@ -6124,15 +6140,15 @@ dependencies = [ [[package]] name = "gix-trace" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cae0e8661c3ff92688ce1c8b8058b3efb312aba9492bbe93661a21705ab431b" +checksum = "04bdde120c29f1fc23a24d3e115aeeea3d60d8e65bab92cc5f9d90d9302eb952" [[package]] name = "gix-utils" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35192df7fd0fa112263bad8021e2df7167df4cc2a6e6d15892e1e55621d3d4dc" +checksum = "ba427e3e9599508ed98a6ddf8ed05493db114564e338e41f6a996d2e4790335f" dependencies = [ "fastrand", "unicode-normalization", @@ -6140,9 +6156,9 @@ dependencies = [ [[package]] name = "gix-validate" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f2badbb64e57b404593ee26b752c26991910fd0d81fe6f9a71c1a8309b6c86" +checksum = "e187b263461bc36cea17650141567753bc6207d036cedd1de6e81a52f277ff68" dependencies = [ "bstr", "thiserror", @@ -6179,7 +6195,7 @@ dependencies = [ "gloo-utils", "http 0.2.12", "js-sys", - "pin-project 1.1.6", + "pin-project 1.1.7", "serde", "serde_json", "thiserror", @@ -6225,7 +6241,7 @@ dependencies = [ "google-cloud-token", "home", "jsonwebtoken 9.3.0", - "reqwest 0.12.8", + "reqwest 0.12.9", "serde", "serde_json", "thiserror", @@ -6241,7 +6257,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04f945a208886a13d07636f38fb978da371d0abc3e34bad338124b9f8c135a8f" dependencies = [ - "reqwest 0.12.8", + "reqwest 0.12.9", "thiserror", "tokio", ] @@ -6266,7 +6282,7 @@ dependencies = [ "percent-encoding", "pkcs8 0.10.2", "regex", - "reqwest 0.12.8", + "reqwest 0.12.9", "reqwest-middleware", "ring 0.17.8", "serde", @@ -6395,6 +6411,12 @@ dependencies = [ "ahash 0.7.8", ] +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + [[package]] name = "hashbrown" version = "0.14.5" @@ -6527,9 +6549,9 @@ dependencies = [ "log", "mac", "markup5ever", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -6694,7 +6716,7 @@ dependencies = [ "hyper 1.5.0", "hyper-util", "log", - "rustls 0.23.15", + "rustls 0.23.16", "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", @@ -6747,9 +6769,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", @@ -6889,7 +6911,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -6994,7 +7016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b23a0c8dfe501baac4adf6ebbfa6eddf8f0c07f56b058cc1288017e32397846c" dependencies = [ "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7097,9 +7119,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jiff" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a45489186a6123c128fdf6016183fcfab7113e1820eb813127e036e287233fb" +checksum = "b9d9d414fc817d3e3d62b2598616733f76c4cc74fbac96069674739b881295c8" dependencies = [ "jiff-tzdb-platform", "windows-sys 0.59.0", @@ -7212,7 +7234,7 @@ version = "18.0.0" source = "git+https://github.com/matter-labs/jsonrpc.git?branch=master#12c53e3e20c09c2fb9966a4ef1b0ea63de172540" dependencies = [ "proc-macro-crate 0.1.5", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -7293,8 +7315,8 @@ dependencies = [ "gloo-net", "http 1.1.0", "jsonrpsee-core", - "pin-project 1.1.6", - "rustls 0.23.15", + "pin-project 1.1.7", + "rustls 0.23.16", "rustls-pki-types", "rustls-platform-verifier", "soketto", @@ -7323,7 +7345,7 @@ dependencies = [ "http-body-util", "jsonrpsee-types", "parking_lot 0.12.3", - "pin-project 1.1.6", + "pin-project 1.1.7", "rand 0.8.5", "rustc-hash 1.1.0", "serde", @@ -7349,7 +7371,7 @@ dependencies = [ "hyper-util", "jsonrpsee-core", "jsonrpsee-types", - "rustls 0.23.15", + "rustls 0.23.16", "rustls-platform-verifier", "serde", "serde_json", @@ -7368,9 +7390,9 @@ checksum = "7895f186d5921065d96e16bd795e5ca89ac8356ec423fafc6e3d7cf8ec11aee4" dependencies = [ "heck", "proc-macro-crate 3.2.0", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7388,7 +7410,7 @@ dependencies = [ "hyper-util", "jsonrpsee-core", "jsonrpsee-types", - "pin-project 1.1.6", + "pin-project 1.1.7", "route-recognizer", "serde", "serde_json", @@ -7579,9 +7601,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libdbus-sys" @@ -7605,9 +7627,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libredox" @@ -7715,10 +7737,10 @@ checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" dependencies = [ "beef", "fnv", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "regex-syntax 0.6.29", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7912,9 +7934,9 @@ version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7923,9 +7945,9 @@ version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8035,9 +8057,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "341014e7f530314e9a1fdbc7400b244efea7122662c96bfa248c31da5bfb2020" dependencies = [ "cfg-if 1.0.0", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8378,9 +8400,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8389,10 +8411,10 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.88", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8440,9 +8462,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "op-alloy-consensus" -version = "0.3.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f7f318f885db6e1455370ca91f74b7faed152c8142f6418f0936d606e582ff" +checksum = "f26c3b35b7b3e36d15e0563eebffe13c1d9ca16b7aaffcb6a64354633547e16b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8456,9 +8478,9 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.3.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "547d29c5ab957ff32e14edddb93652dad748d2ef6cbe4b0fe8615ce06b0a3ddb" +checksum = "94bae9bf91b620e1e2c2291562e5998bc1247bd8ada011773e1997b31a95de99" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8497,7 +8519,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" dependencies = [ "bytes", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -8516,9 +8538,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.67" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8cefcf97f41316955f9294cd61f639bdcfa9f2f230faac6cb896aa8ab64704" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if 1.0.0", @@ -8535,9 +8557,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8548,9 +8570,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.3.2+3.3.2" +version = "300.4.0+3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" +checksum = "a709e02f2b4aca747929cca5ed248880847c650233cf8b8cdc48f40aaf4898a6" dependencies = [ "cc", ] @@ -8604,7 +8626,7 @@ dependencies = [ "bytes", "http 1.1.0", "opentelemetry", - "reqwest 0.12.8", + "reqwest 0.12.9", ] [[package]] @@ -8621,7 +8643,7 @@ dependencies = [ "opentelemetry-proto", "opentelemetry_sdk", "prost 0.13.3", - "reqwest 0.12.8", + "reqwest 0.12.9", "thiserror", "tokio", "tonic", @@ -8757,7 +8779,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -8769,7 +8791,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ "proc-macro-crate 3.2.0", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -8890,10 +8912,10 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "proc-macro2-diagnostics", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8965,9 +8987,9 @@ checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -9049,9 +9071,9 @@ checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator 0.11.2", "phf_shared 0.11.2", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -9083,11 +9105,11 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ - "pin-project-internal 1.1.6", + "pin-project-internal 1.1.7", ] [[package]] @@ -9096,27 +9118,27 @@ version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "851c8d0ce9bebe43790dedfc86614c23494ac9f423dd618d3a61fc693eafe61e" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "pin-project-internal" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -9226,12 +9248,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.22" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ - "proc-macro2 1.0.88", - "syn 2.0.79", + "proc-macro2 1.0.89", + "syn 2.0.87", ] [[package]] @@ -9305,7 +9327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", "version_check", @@ -9317,7 +9339,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "version_check", ] @@ -9328,7 +9350,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", ] @@ -9339,9 +9361,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" dependencies = [ "proc-macro-error-attr2", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -9361,9 +9383,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -9374,9 +9396,9 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", "version_check", "yansi 1.0.1", ] @@ -9430,9 +9452,9 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -9461,9 +9483,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -9503,7 +9525,7 @@ dependencies = [ "prost 0.12.6", "prost-types 0.12.6", "regex", - "syn 2.0.79", + "syn 2.0.87", "tempfile", ] @@ -9515,9 +9537,9 @@ checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", "itertools 0.12.1", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -9528,9 +9550,9 @@ checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", "itertools 0.13.0", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -9629,7 +9651,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -9737,7 +9759,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.15", + "rustls 0.23.16", "socket2", "thiserror", "tokio", @@ -9754,7 +9776,7 @@ dependencies = [ "rand 0.8.5", "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.15", + "rustls 0.23.16", "slab", "thiserror", "tinyvec", @@ -9763,10 +9785,11 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" +checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780" dependencies = [ + "cfg_aliases 0.2.1", "libc", "once_cell", "socket2", @@ -9789,7 +9812,7 @@ version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", ] [[package]] @@ -10010,9 +10033,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -10113,9 +10136,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.8" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "async-compression", "base64 0.22.1", @@ -10142,7 +10165,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.15", + "rustls 0.23.16", "rustls-native-certs 0.8.0", "rustls-pemfile 2.2.0", "rustls-pki-types", @@ -10175,7 +10198,7 @@ dependencies = [ "anyhow", "async-trait", "http 1.1.0", - "reqwest 0.12.8", + "reqwest 0.12.9", "serde", "thiserror", "tower-service", @@ -10208,9 +10231,9 @@ dependencies = [ [[package]] name = "revm" -version = "14.0.3" +version = "17.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "641702b12847f9ed418d552f4fcabe536d867a2c980e96b6e7e25d7b992f929f" +checksum = "055bee6a81aaeee8c2389ae31f0d4de87f44df24f4444a1116f9755fd87a76ad" dependencies = [ "auto_impl", "cfg-if 1.0.0", @@ -10223,9 +10246,9 @@ dependencies = [ [[package]] name = "revm-inspectors" -version = "0.8.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c44af0bf801f48d25f7baf25cf72aff4c02d610f83b428175228162fef0246" +checksum = "1e29c662f7887f3b659d4b0fd234673419a8fcbeaa1ecc29bf7034c0a75cc8ea" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -10241,9 +10264,9 @@ dependencies = [ [[package]] name = "revm-interpreter" -version = "10.0.3" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5e14002afae20b5bf1566f22316122f42f57517000e559c55b25bf7a49cba2" +checksum = "fac2034454f8bc69dc7d3c94cdb1b57559e27f5ef0518771f1787de543d7d6a1" dependencies = [ "revm-primitives", "serde", @@ -10251,9 +10274,9 @@ dependencies = [ [[package]] name = "revm-precompile" -version = "11.0.3" +version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3198c06247e8d4ad0d1312591edf049b0de4ddffa9fecb625c318fd67db8639b" +checksum = "7a88c8c7c5f9b988a9e65fc0990c6ce859cdb74114db705bd118a96d22d08027" dependencies = [ "aurora-engine-modexp", "blst", @@ -10271,9 +10294,9 @@ dependencies = [ [[package]] name = "revm-primitives" -version = "10.0.0" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f1525851a03aff9a9d6a1d018b414d76252d6802ab54695b27093ecd7e7a101" +checksum = "0d11fa1e195b0bebaf3fb18596f314a13ba3a4cb1fdd16d3465934d812fd921e" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -10382,7 +10405,7 @@ version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -10404,7 +10427,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -10570,9 +10593,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" dependencies = [ "bitflags 2.6.0", "errno", @@ -10595,9 +10618,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.15" +version = "0.23.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" dependencies = [ "aws-lc-rs", "log", @@ -10682,7 +10705,7 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.15", + "rustls 0.23.16", "rustls-native-certs 0.7.3", "rustls-platform-verifier-android", "rustls-webpki 0.102.8", @@ -10796,33 +10819,33 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.11.3" +version = "2.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +checksum = "1aa7ffc1c0ef49b0452c6e2986abf2b07743320641ffd5fc63d552458e3b779b" dependencies = [ "cfg-if 1.0.0", - "derive_more 0.99.18", + "derive_more 1.0.0", "parity-scale-codec 3.6.12", "scale-info-derive", ] [[package]] name = "scale-info-derive" -version = "2.11.3" +version = "2.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +checksum = "46385cc24172cf615450267463f937c10072516359b3ff1cb24228a4a08bf951" dependencies = [ "proc-macro-crate 3.2.0", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] name = "scc" -version = "2.2.2" +version = "2.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c1f7fc6deb21665a9060dfc7d271be784669295a31babdcd4dd2c79ae8cbfb" +checksum = "d8d25269dd3a12467afe2e510f69fb0b46b698e5afb296b59f2145259deaf8e8" dependencies = [ "sdd", ] @@ -10854,10 +10877,21 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "serde_derive_internals", - "syn 2.0.79", + "syn 2.0.87", +] + +[[package]] +name = "schnellru" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" +dependencies = [ + "ahash 0.8.11", + "cfg-if 1.0.0", + "hashbrown 0.13.2", ] [[package]] @@ -11172,9 +11206,9 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] @@ -11191,13 +11225,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -11206,16 +11240,16 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "indexmap 2.6.0", "itoa", @@ -11250,9 +11284,9 @@ version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -11295,7 +11329,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ "darling 0.13.4", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -11333,9 +11367,9 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -11594,9 +11628,9 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "snapbox" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba434818a8a9b1b106404288d6bd75a94348aae8fc9a518b211b609a36a54bc" +checksum = "881f1849454828a68363dd288b7a0a071e55e2a4356d2c38b567db18a9be0d9f" dependencies = [ "anstream", "anstyle", @@ -11688,7 +11722,7 @@ dependencies = [ "path-slash", "rayon", "regex", - "reqwest 0.12.8", + "reqwest 0.12.9", "sanitize-filename", "semver 1.0.23", "serde", @@ -11816,11 +11850,11 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "sqlx-core", "sqlx-macros-core", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -11834,7 +11868,7 @@ dependencies = [ "heck", "hex", "once_cell", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "serde", "serde_json", @@ -11843,7 +11877,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.79", + "syn 2.0.87", "tempfile", "tokio", "url", @@ -12001,7 +12035,7 @@ checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" dependencies = [ "phf_generator 0.10.0", "phf_shared 0.10.0", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", ] @@ -12053,10 +12087,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "rustversion", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -12107,7 +12141,7 @@ dependencies = [ "const-hex", "dirs 5.0.1", "fs4 0.10.0", - "reqwest 0.12.8", + "reqwest 0.12.9", "semver 1.0.23", "serde", "serde_json", @@ -12148,32 +12182,32 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.79" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "unicode-ident", ] [[package]] name = "syn-solidity" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebfc1bfd06acc78f16d8fd3ef846bc222ee7002468d10a7dce8d703d6eab89a3" +checksum = "16320d4a2021ba1a32470b3759676114a918885e9800e68ad60f2c67969fba62" dependencies = [ "paste", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -12183,9 +12217,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -12343,22 +12377,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -12468,9 +12502,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" dependencies = [ "backtrace", "bytes", @@ -12490,9 +12524,9 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -12521,7 +12555,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.15", + "rustls 0.23.16", "rustls-pki-types", "tokio", ] @@ -12573,7 +12607,7 @@ checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", - "rustls 0.23.15", + "rustls 0.23.16", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -12683,7 +12717,7 @@ dependencies = [ "hyper-timeout", "hyper-util", "percent-encoding", - "pin-project 1.1.6", + "pin-project 1.1.7", "prost 0.13.3", "rustls-native-certs 0.8.0", "rustls-pemfile 2.2.0", @@ -12712,7 +12746,7 @@ dependencies = [ "futures-core", "futures-util", "indexmap 1.9.3", - "pin-project 1.1.6", + "pin-project 1.1.7", "pin-project-lite", "rand 0.8.5", "slab", @@ -12806,9 +12840,9 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -12837,7 +12871,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ - "pin-project 1.1.6", + "pin-project 1.1.7", "tracing", ] @@ -12992,7 +13026,7 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "rustls 0.23.15", + "rustls 0.23.16", "rustls-pki-types", "sha1", "thiserror", @@ -13055,12 +13089,9 @@ dependencies = [ [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" @@ -13302,9 +13333,9 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a511871dc5de990a3b2a0e715facfbc5da848c0c0395597a1415029fb7c250a" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -13329,7 +13360,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", ] @@ -13399,9 +13430,9 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -13433,9 +13464,9 @@ version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -13448,9 +13479,9 @@ checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-streams" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -13459,6 +13490,20 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasmtimer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7ed9d8b15c7fb594d72bfb4b5a276f3d2029333cd93a932f376f5937f6f80ee" +dependencies = [ + "futures 0.3.31", + "js-sys", + "parking_lot 0.12.3", + "pin-utils", + "slab", + "wasm-bindgen", +] + [[package]] name = "watchexec" version = "4.1.0" @@ -13688,9 +13733,9 @@ version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -13699,9 +13744,9 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -13710,9 +13755,9 @@ version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -13721,9 +13766,9 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -14018,9 +14063,9 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -14038,9 +14083,9 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -14160,9 +14205,9 @@ dependencies = [ [[package]] name = "zk_evm" -version = "0.150.6" +version = "0.150.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c14bda6c101389145cd01fac900f1392876bc0284d98faf7f376237baa2cb19d" +checksum = "3cc74fbe2b45fd19e95c59ea792c795feebdb616ebaa463f0ac567f495f47387" dependencies = [ "anyhow", "lazy_static", @@ -14170,7 +14215,7 @@ dependencies = [ "serde", "serde_json", "static_assertions", - "zk_evm_abstractions 0.150.6", + "zk_evm_abstractions 0.150.7", ] [[package]] @@ -14201,15 +14246,15 @@ dependencies = [ [[package]] name = "zk_evm_abstractions" -version = "0.150.6" +version = "0.150.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a008f2442fc6a508bdd1f902380242cb6ff11b8b27acdac2677c6d9f75cbb004" +checksum = "37f333a3b059899df09e40deb041af881bc03e496fda5eec618ffb5e854ee7df" dependencies = [ "anyhow", "num_enum 0.6.1", "serde", "static_assertions", - "zkevm_opcode_defs 0.150.6", + "zkevm_opcode_defs 0.150.7", ] [[package]] @@ -14258,9 +14303,9 @@ dependencies = [ [[package]] name = "zkevm_circuits" -version = "0.150.6" +version = "0.150.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f68518aedd5358b17224771bb78bacd912cf66011aeda98b1f887cfb9e0972f" +checksum = "d06fb35b00699d25175a2ad447f86a9088af8b0bc698bb57086fb04c13e52eab" dependencies = [ "arrayvec 0.7.6", "boojum", @@ -14272,7 +14317,7 @@ dependencies = [ "seq-macro", "serde", "smallvec", - "zkevm_opcode_defs 0.150.6", + "zkevm_opcode_defs 0.150.7", "zksync_cs_derive", ] @@ -14320,25 +14365,9 @@ dependencies = [ [[package]] name = "zkevm_opcode_defs" -version = "0.150.0" -source = "git+https://github.com/matter-labs/era-zkevm_opcode_defs.git?branch=v1.5.0#cf5f9c18c580f845b32fc2a4d565a77380fd15bc" -dependencies = [ - "bitflags 2.6.0", - "blake2 0.10.6", - "ethereum-types 0.14.1", - "k256 0.13.4", - "lazy_static", - "p256", - "serde", - "sha2 0.10.8", - "sha3 0.10.8", -] - -[[package]] -name = "zkevm_opcode_defs" -version = "0.150.6" +version = "0.150.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "762b5f1c1b283c5388995a85d40a05aef1c14f50eb904998b7e9364739f5b899" +checksum = "b83f3b279248af4ca86dec20a54127f02110b45570f3f6c1d13df49ba75c28a5" dependencies = [ "bitflags 2.6.0", "blake2 0.10.6", @@ -14375,7 +14404,7 @@ dependencies = [ [[package]] name = "zksync_basic_types" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "chrono", @@ -14423,7 +14452,7 @@ checksum = "035269d811b3770debca372141ab64cad067dce8e58cb39a48cb7617d30c626b" dependencies = [ "anyhow", "once_cell", - "pin-project 1.1.6", + "pin-project 1.1.7", "rand 0.8.5", "sha3 0.10.8", "thiserror", @@ -14437,7 +14466,7 @@ dependencies = [ [[package]] name = "zksync_config" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "rand 0.8.5", @@ -14532,7 +14561,7 @@ dependencies = [ [[package]] name = "zksync_contracts" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "envy", "ethabi 18.0.0", @@ -14546,7 +14575,7 @@ dependencies = [ [[package]] name = "zksync_crypto_primitives" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "blake2 0.10.6", @@ -14568,7 +14597,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5939e2df4288c263c706ff18ac718e984149223ad4289d6d957d767dcfc04c81" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "syn 1.0.109", ] @@ -14576,7 +14605,7 @@ dependencies = [ [[package]] name = "zksync_dal" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "bigdecimal 0.4.5", @@ -14613,7 +14642,7 @@ dependencies = [ [[package]] name = "zksync_db_connection" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "rand 0.8.5", @@ -14649,7 +14678,7 @@ dependencies = [ "num-bigint 0.4.6", "num-integer", "num-traits", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "quote 1.0.37", "serde", "syn 1.0.109", @@ -14657,9 +14686,9 @@ dependencies = [ [[package]] name = "zksync_kzg" -version = "0.150.6" +version = "0.150.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c006b6b7a27cc50ff0c515b6d0b197dbb907bbf65d1d2ea42fc3ed21b315642" +checksum = "dc58af8e4e4ad1a851ffd2275e6a44ead0f15a7eaac9dc9d60a56b3b9c9b08e8" dependencies = [ "boojum", "derivative", @@ -14669,13 +14698,13 @@ dependencies = [ "serde", "serde_json", "serde_with", - "zkevm_circuits 0.150.6", + "zkevm_circuits 0.150.7", ] [[package]] name = "zksync_l1_contract_interface" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "hex", @@ -14691,7 +14720,7 @@ dependencies = [ [[package]] name = "zksync_mini_merkle_tree" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "once_cell", "zksync_basic_types", @@ -14701,14 +14730,14 @@ dependencies = [ [[package]] name = "zksync_multivm" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "circuit_sequencer_api 0.133.1", "circuit_sequencer_api 0.140.3", "circuit_sequencer_api 0.141.2", "circuit_sequencer_api 0.142.2", - "circuit_sequencer_api 0.150.6", + "circuit_sequencer_api 0.150.7", "ethabi 18.0.0", "hex", "itertools 0.10.5", @@ -14720,8 +14749,9 @@ dependencies = [ "zk_evm 0.133.0", "zk_evm 0.140.0", "zk_evm 0.141.0", - "zk_evm 0.150.6", + "zk_evm 0.150.7", "zksync_contracts", + "zksync_mini_merkle_tree", "zksync_system_constants", "zksync_types", "zksync_utils", @@ -14732,7 +14762,7 @@ dependencies = [ [[package]] name = "zksync_object_store" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "async-trait", @@ -14743,7 +14773,7 @@ dependencies = [ "http 1.1.0", "prost 0.12.6", "rand 0.8.5", - "reqwest 0.12.8", + "reqwest 0.12.9", "serde_json", "tokio", "tracing", @@ -14796,21 +14826,21 @@ dependencies = [ "anyhow", "heck", "prettyplease", - "proc-macro2 1.0.88", + "proc-macro2 1.0.89", "prost-build", "prost-reflect", "protox", "quote 1.0.37", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "zksync_prover_interface" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "chrono", - "circuit_sequencer_api 0.150.6", + "circuit_sequencer_api 0.150.7", "serde", "serde_with", "strum", @@ -14822,7 +14852,7 @@ dependencies = [ [[package]] name = "zksync_shared_metrics" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "rustc_version 0.4.1", "tracing", @@ -14851,7 +14881,7 @@ dependencies = [ [[package]] name = "zksync_state" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "async-trait", @@ -14874,7 +14904,7 @@ dependencies = [ [[package]] name = "zksync_storage" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "num_cpus", "once_cell", @@ -14887,7 +14917,7 @@ dependencies = [ [[package]] name = "zksync_system_constants" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "once_cell", "zksync_basic_types", @@ -14897,7 +14927,7 @@ dependencies = [ [[package]] name = "zksync_types" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "bigdecimal 0.4.5", @@ -14930,7 +14960,7 @@ dependencies = [ [[package]] name = "zksync_utils" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "bigdecimal 0.4.5", @@ -14938,7 +14968,7 @@ dependencies = [ "hex", "num", "once_cell", - "reqwest 0.12.8", + "reqwest 0.12.9", "serde", "serde_json", "thiserror", @@ -14952,7 +14982,7 @@ dependencies = [ [[package]] name = "zksync_vlog" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "chrono", @@ -14982,8 +15012,8 @@ source = "git+https://github.com/matter-labs/vm2.git?rev=df5bec3d04d64d434f9b0cc dependencies = [ "enum_dispatch", "primitive-types 0.12.2", - "zk_evm_abstractions 0.150.6", - "zkevm_opcode_defs 0.150.6", + "zk_evm_abstractions 0.150.7", + "zkevm_opcode_defs 0.150.7", "zksync_vm2_interface", ] @@ -14998,7 +15028,7 @@ dependencies = [ [[package]] name = "zksync_vm_interface" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "async-trait", @@ -15015,7 +15045,7 @@ dependencies = [ [[package]] name = "zksync_web3_decl" version = "0.1.0" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=cfbcc11be0826e8c55fafa84ae01b2aead25d127#cfbcc11be0826e8c55fafa84ae01b2aead25d127" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=6c034f6e180cc92e99766f14c8840c90efa56cec#6c034f6e180cc92e99766f14c8840c90efa56cec" dependencies = [ "anyhow", "async-trait", @@ -15023,7 +15053,7 @@ dependencies = [ "jsonrpsee", "pin-project-lite", "rlp", - "rustls 0.23.15", + "rustls 0.23.16", "serde", "serde_json", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index af3a4915a..eeb2f5ecc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -179,73 +179,78 @@ foundry-zksync-inspectors = { path = "crates/zksync/inspectors" } # foundry-compilers = { version = "0.11.1", default-features = false } # foundry-fork-db = "0.3" foundry-block-explorers = { git = "https://github.com/Moonsong-Labs/block-explorers", branch = "zksync-v0.7.3", default-features = false } -foundry-compilers = { git = "https://github.com/Moonsong-Labs/compilers", branch = "zksync-v0.11.4" } -foundry-fork-db = { git = "https://github.com/Moonsong-Labs/foundry-zksync-fork-db", branch = "zksync-v0.4.0" } +foundry-compilers = { git = "https://github.com/Moonsong-Labs/compilers", branch = "zksync-v0.11.6" } +foundry-fork-db = { git = "https://github.com/Moonsong-Labs/foundry-zksync-fork-db", branch = "zksync-v0.6.0" } solang-parser = "=0.3.3" ## revm -revm = { version = "14.0.3", default-features = false } -revm-primitives = { version = "10.0.0", default-features = false } -revm-inspectors = { version = "0.8.0", features = ["serde"] } +revm = { version = "17.1.0", default-features = false } +revm-primitives = { version = "13.0.0", default-features = false } +revm-inspectors = { version = "0.10.0", features = ["serde"] } ## ethers ethers-contract-abigen = { version = "2.0.14", default-features = false } ## alloy -alloy-consensus = { version = "0.4.2", default-features = false } -alloy-contract = { version = "0.4.2", default-features = false } -alloy-eips = { version = "0.4.2", default-features = false } -alloy-genesis = { version = "0.4.2", default-features = false } -alloy-json-rpc = { version = "0.4.2", default-features = false } -alloy-network = { version = "0.4.2", default-features = false } -alloy-provider = { version = "0.4.2", default-features = false } -alloy-pubsub = { version = "0.4.2", default-features = false } -alloy-rpc-client = { version = "0.4.2", default-features = false } -alloy-rpc-types = { version = "0.4.2", default-features = true } -alloy-serde = { version = "0.4.2", default-features = false } -alloy-signer = { version = "0.4.2", default-features = false } -alloy-signer-aws = { version = "0.4.2", default-features = false } -alloy-signer-gcp = { version = "0.4.2", default-features = false } -alloy-signer-ledger = { version = "0.4.2", default-features = false } -alloy-signer-local = { version = "0.4.2", default-features = false } -alloy-signer-trezor = { version = "0.4.2", default-features = false } -alloy-transport = { version = "0.4.2", default-features = false } -alloy-transport-http = { version = "0.4.2", default-features = false } -alloy-transport-ipc = { version = "0.4.2", default-features = false } -alloy-transport-ws = { version = "0.4.2", default-features = false } +alloy-consensus = { version = "0.5.4", default-features = false } +alloy-contract = { version = "0.5.4", default-features = false } +alloy-eips = { version = "0.5.4", default-features = false } +alloy-genesis = { version = "0.5.4", default-features = false } +alloy-json-rpc = { version = "0.5.4", default-features = false } +alloy-network = { version = "0.5.4", default-features = false } +alloy-provider = { version = "0.5.4", default-features = false } +alloy-pubsub = { version = "0.5.4", default-features = false } +alloy-rpc-client = { version = "0.5.4", default-features = false } +alloy-rpc-types = { version = "0.5.4", default-features = true } +alloy-serde = { version = "0.5.4", default-features = false } +alloy-signer = { version = "0.5.4", default-features = false } +alloy-signer-aws = { version = "0.5.4", default-features = false } +alloy-signer-gcp = { version = "0.5.4", default-features = false } +alloy-signer-ledger = { version = "0.5.4", default-features = false } +alloy-signer-local = { version = "0.5.4", default-features = false } +alloy-signer-trezor = { version = "0.5.4", default-features = false } +alloy-transport = { version = "0.5.4", default-features = false } +alloy-transport-http = { version = "0.5.4", default-features = false } +alloy-transport-ipc = { version = "0.5.4", default-features = false } +alloy-transport-ws = { version = "0.5.4", default-features = false } ## alloy-core -alloy-dyn-abi = "0.8.5" -alloy-json-abi = "0.8.5" -alloy-primitives = { version = "0.8.5", features = [ +alloy-dyn-abi = "0.8.9" +alloy-json-abi = "0.8.9" +alloy-primitives = { version = "0.8.9", features = [ "getrandom", "rand", "map-foldhash", ] } -alloy-sol-macro-expander = "0.8.5" -alloy-sol-macro-input = "0.8.5" -alloy-sol-types = "0.8.5" -syn-solidity = "0.8.5" +alloy-sol-macro-expander = "0.8.9" +alloy-sol-macro-input = "0.8.9" +alloy-sol-types = "0.8.9" +syn-solidity = "0.8.9" alloy-chains = "0.1" alloy-rlp = "0.3" alloy-trie = "0.6.0" ## op-alloy -op-alloy-rpc-types = "0.3.3" -op-alloy-consensus = "0.3.3" +op-alloy-rpc-types = "0.5.0" +op-alloy-consensus = "0.5.0" + +## cli +anstream = "0.6.15" +anstyle = "1.0.8" +terminal_size = "0.4" ## zksync -era_test_node = { git="https://github.com/matter-labs/era-test-node.git" , rev = "56c4e92693b5dd5ab166e368b066d9169b438855" } +era_test_node = { git="https://github.com/matter-labs/era-test-node.git" , rev = "94503847b402f0161c3372d5f357a4cb16a2d66d" } zksync-web3-rs = {git = "https://github.com/jrigada/zksync-web3-rs.git", rev = "bc3e6d3e75b7ff3747ff2dccefa9fb74d770931b"} # zksync-web3-rs = {git = "https://github.com/lambdaclass/zksync-web3-rs.git", rev = "56653345d14331e0865a6785c77cdda63c94eeba"} -zksync_basic_types = { git = "https://github.com/matter-labs/zksync-era.git", rev = "cfbcc11be0826e8c55fafa84ae01b2aead25d127" } -zksync_types = { git = "https://github.com/matter-labs/zksync-era.git", rev = "cfbcc11be0826e8c55fafa84ae01b2aead25d127" } -zksync_state = { git = "https://github.com/matter-labs/zksync-era.git", rev = "cfbcc11be0826e8c55fafa84ae01b2aead25d127" } -zksync_multivm = { git = "https://github.com/matter-labs/zksync-era.git", rev = "cfbcc11be0826e8c55fafa84ae01b2aead25d127" } -zksync_web3_decl = { git = "https://github.com/matter-labs/zksync-era.git", rev = "cfbcc11be0826e8c55fafa84ae01b2aead25d127" } -zksync_utils = { git = "https://github.com/matter-labs/zksync-era.git", rev = "cfbcc11be0826e8c55fafa84ae01b2aead25d127" } -zksync_contracts = { git = "https://github.com/matter-labs/zksync-era.git", rev = "cfbcc11be0826e8c55fafa84ae01b2aead25d127" } +zksync_basic_types = { git = "https://github.com/matter-labs/zksync-era.git", rev = "6c034f6e180cc92e99766f14c8840c90efa56cec" } +zksync_types = { git = "https://github.com/matter-labs/zksync-era.git", rev = "6c034f6e180cc92e99766f14c8840c90efa56cec" } +zksync_state = { git = "https://github.com/matter-labs/zksync-era.git", rev = "6c034f6e180cc92e99766f14c8840c90efa56cec" } +zksync_multivm = { git = "https://github.com/matter-labs/zksync-era.git", rev = "6c034f6e180cc92e99766f14c8840c90efa56cec" } +zksync_web3_decl = { git = "https://github.com/matter-labs/zksync-era.git", rev = "6c034f6e180cc92e99766f14c8840c90efa56cec" } +zksync_utils = { git = "https://github.com/matter-labs/zksync-era.git", rev = "6c034f6e180cc92e99766f14c8840c90efa56cec" } +zksync_contracts = { git = "https://github.com/matter-labs/zksync-era.git", rev = "6c034f6e180cc92e99766f14c8840c90efa56cec" } # macros proc-macro2 = "1.0.82" @@ -344,27 +349,27 @@ yansi = { version = "1.0", features = ["detect-tty", "detect-env"] } # alloy-transport-ipc = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" } # alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", rev = "7fab7ee" } -alloy-consensus = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-contract = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-eips = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-genesis = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-json-rpc = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-network = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-network-primitives = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-provider = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-pubsub = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-rpc-client = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-rpc-types = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-rpc-types-trace = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-rpc-types-eth = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-serde = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-signer = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-signer-aws = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-signer-gcp = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-signer-ledger = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-signer-local = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-signer-trezor = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-transport = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-transport-http = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-transport-ipc = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } -alloy-transport-ws = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.4.2" } +alloy-consensus = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-contract = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-eips = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-genesis = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-json-rpc = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-network = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-network-primitives = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-provider = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-pubsub = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-rpc-client = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-rpc-types = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-rpc-types-trace = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-rpc-types-eth = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-serde = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-signer = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-signer-aws = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-signer-gcp = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-signer-ledger = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-signer-local = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-signer-trezor = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-transport = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-transport-http = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-transport-ipc = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } +alloy-transport-ws = { git = "https://github.com/Karrq/alloy", branch = "zksync-v0.5.4" } diff --git a/SECURITY.md b/SECURITY.md index 5260d529f..bea27ad11 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,4 +2,4 @@ ## Reporting a Vulnerability -Contact georgios at paradigm.xyz. +Contact [security@ithaca.xyz](mailto:security@ithaca.xyz). diff --git a/clippy.toml b/clippy.toml index 92b35ffc0..3e45486a8 100644 --- a/clippy.toml +++ b/clippy.toml @@ -2,3 +2,11 @@ msrv = "1.80" # bytes::Bytes is included by default and alloy_primitives::Bytes is a wrapper around it, # so it is safe to ignore it as well ignore-interior-mutability = ["bytes::Bytes", "alloy_primitives::Bytes"] + +# disallowed-macros = [ +# # See `foundry_common::shell` +# { path = "std::print", reason = "use `sh_print` or similar macros instead" }, +# { path = "std::eprint", reason = "use `sh_eprint` or similar macros instead" }, +# { path = "std::println", reason = "use `sh_println` or similar macros instead" }, +# { path = "std::eprintln", reason = "use `sh_eprintln` or similar macros instead" }, +# ] diff --git a/crates/anvil/core/Cargo.toml b/crates/anvil/core/Cargo.toml index 6ea5e5318..da337c62d 100644 --- a/crates/anvil/core/Cargo.toml +++ b/crates/anvil/core/Cargo.toml @@ -38,6 +38,7 @@ bytes = "1.4" # misc rand = "0.8" +thiserror.workspace = true [features] default = ["serde"] diff --git a/crates/anvil/core/src/eth/block.rs b/crates/anvil/core/src/eth/block.rs index 337c5cfd8..c9f9048b8 100644 --- a/crates/anvil/core/src/eth/block.rs +++ b/crates/anvil/core/src/eth/block.rs @@ -2,7 +2,7 @@ use super::{ transaction::{TransactionInfo, TypedReceipt}, trie, }; -use alloy_consensus::Header; +use alloy_consensus::{Header, EMPTY_OMMER_ROOT_HASH}; use alloy_eips::eip2718::Encodable2718; use alloy_primitives::{Address, Bloom, Bytes, B256, B64, U256}; use alloy_rlp::{RlpDecodable, RlpEncodable}; @@ -34,19 +34,11 @@ impl Block { /// /// Note: if the `impersonate-tx` feature is enabled this will also accept /// `MaybeImpersonatedTransaction`. - pub fn new( - partial_header: PartialHeader, - transactions: impl IntoIterator, - ommers: Vec
, - ) -> Self + pub fn new(partial_header: PartialHeader, transactions: impl IntoIterator) -> Self where T: Into, { let transactions: Vec<_> = transactions.into_iter().map(Into::into).collect(); - let mut encoded_ommers: Vec = Vec::new(); - alloy_rlp::encode_list(&ommers, &mut encoded_ommers); - let ommers_hash = - B256::from_slice(alloy_primitives::utils::keccak256(encoded_ommers).as_slice()); let transactions_root = trie::ordered_trie_root(transactions.iter().map(|r| r.encoded_2718())); @@ -54,7 +46,7 @@ impl Block { header: Header { parent_hash: partial_header.parent_hash, beneficiary: partial_header.beneficiary, - ommers_hash, + ommers_hash: EMPTY_OMMER_ROOT_HASH, state_root: partial_header.state_root, transactions_root, receipts_root: partial_header.receipts_root, @@ -66,16 +58,16 @@ impl Block { timestamp: partial_header.timestamp, extra_data: partial_header.extra_data, mix_hash: partial_header.mix_hash, - withdrawals_root: None, + withdrawals_root: partial_header.withdrawals_root, blob_gas_used: partial_header.blob_gas_used, excess_blob_gas: partial_header.excess_blob_gas, parent_beacon_block_root: partial_header.parent_beacon_block_root, nonce: partial_header.nonce, base_fee_per_gas: partial_header.base_fee, - requests_root: None, + requests_hash: partial_header.requests_hash, }, transactions, - ommers, + ommers: vec![], } } } @@ -100,6 +92,8 @@ pub struct PartialHeader { pub parent_beacon_block_root: Option, pub nonce: B64, pub base_fee: Option, + pub withdrawals_root: Option, + pub requests_hash: Option, } impl From
for PartialHeader { @@ -122,6 +116,8 @@ impl From
for PartialHeader { blob_gas_used: value.blob_gas_used, excess_blob_gas: value.excess_blob_gas, parent_beacon_block_root: value.parent_beacon_block_root, + requests_hash: value.requests_hash, + withdrawals_root: value.withdrawals_root, } } } @@ -160,7 +156,7 @@ mod tests { excess_blob_gas: Default::default(), parent_beacon_block_root: Default::default(), base_fee_per_gas: None, - requests_root: None, + requests_hash: None, }; let encoded = alloy_rlp::encode(&header); @@ -201,7 +197,7 @@ mod tests { parent_beacon_block_root: None, nonce: B64::ZERO, base_fee_per_gas: None, - requests_root: None, + requests_hash: None, }; header.encode(&mut data); @@ -234,7 +230,7 @@ mod tests { excess_blob_gas: None, parent_beacon_block_root: None, base_fee_per_gas: None, - requests_root: None, + requests_hash: None, }; let header = Header::decode(&mut data.as_slice()).unwrap(); assert_eq!(header, expected); @@ -266,7 +262,7 @@ mod tests { blob_gas_used: None, excess_blob_gas: None, parent_beacon_block_root: None, - requests_root: None, + requests_hash: None, }; assert_eq!(header.hash_slow(), expected_hash); } diff --git a/crates/anvil/core/src/eth/mod.rs b/crates/anvil/core/src/eth/mod.rs index d53473666..73c133b2c 100644 --- a/crates/anvil/core/src/eth/mod.rs +++ b/crates/anvil/core/src/eth/mod.rs @@ -19,6 +19,7 @@ pub mod subscription; pub mod transaction; pub mod trie; pub mod utils; +pub mod wallet; #[cfg(feature = "serde")] pub mod serde_helpers; @@ -769,6 +770,31 @@ pub enum EthRequest { /// Reorg the chain #[cfg_attr(feature = "serde", serde(rename = "anvil_reorg",))] Reorg(ReorgOptions), + + /// Wallet + #[cfg_attr(feature = "serde", serde(rename = "wallet_getCapabilities", with = "empty_params"))] + WalletGetCapabilities(()), + + /// Wallet send_tx + #[cfg_attr( + feature = "serde", + serde( + rename = "wallet_sendTransaction", + alias = "odyssey_sendTransaction", + with = "sequence" + ) + )] + WalletSendTransaction(Box>), + + /// Add an address to the [`DelegationCapability`] of the wallet + /// + /// [`DelegationCapability`]: wallet::DelegationCapability + #[cfg_attr(feature = "serde", serde(rename = "anvil_addCapability", with = "sequence"))] + AnvilAddCapability(Address), + + /// Set the executor (sponsor) wallet + #[cfg_attr(feature = "serde", serde(rename = "anvil_setExecutor", with = "sequence"))] + AnvilSetExecutor(String), } /// Represents ethereum JSON-RPC API diff --git a/crates/anvil/core/src/eth/transaction/mod.rs b/crates/anvil/core/src/eth/transaction/mod.rs index c31207920..827f14a55 100644 --- a/crates/anvil/core/src/eth/transaction/mod.rs +++ b/crates/anvil/core/src/eth/transaction/mod.rs @@ -300,7 +300,7 @@ pub fn to_alloy_transaction_with_hash_and_sender( y_parity: None, }), access_list: None, - transaction_type: None, + transaction_type: Some(0), max_fee_per_blob_gas: None, blob_versioned_hashes: None, authorization_list: None, @@ -1637,7 +1637,6 @@ pub fn convert_to_anvil_receipt(receipt: AnyTransactionReceipt) -> Option Option TypedReceipt::Legacy(receipt_with_bloom), @@ -1896,4 +1894,28 @@ mod tests { assert_eq!(receipt, expected); } + + #[test] + fn deser_to_type_tx() { + let tx = r#" + { + "EIP1559": { + "chainId": "0x7a69", + "nonce": "0x0", + "gas": "0x5209", + "maxFeePerGas": "0x77359401", + "maxPriorityFeePerGas": "0x1", + "to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "value": "0x0", + "accessList": [], + "input": "0x", + "r": "0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0", + "s": "0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd", + "yParity": "0x0", + "hash": "0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515" + } + }"#; + + let _typed_tx: TypedTransaction = serde_json::from_str(tx).unwrap(); + } } diff --git a/crates/anvil/core/src/eth/wallet.rs b/crates/anvil/core/src/eth/wallet.rs new file mode 100644 index 000000000..8676ec2fb --- /dev/null +++ b/crates/anvil/core/src/eth/wallet.rs @@ -0,0 +1,79 @@ +use alloy_primitives::{map::HashMap, Address, ChainId, U64}; +use serde::{Deserialize, Serialize}; + +/// The capability to perform [EIP-7702][eip-7702] delegations, sponsored by the sequencer. +/// +/// The sequencer will only perform delegations, and act on behalf of delegated accounts, if the +/// account delegates to one of the addresses specified within this capability. +/// +/// [eip-7702]: https://eips.ethereum.org/EIPS/eip-7702 +#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Default)] +pub struct DelegationCapability { + /// A list of valid delegation contracts. + pub addresses: Vec
, +} + +/// Wallet capabilities for a specific chain. +#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Default)] +pub struct Capabilities { + /// The capability to delegate. + pub delegation: DelegationCapability, +} + +/// A map of wallet capabilities per chain ID. +#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Default)] +pub struct WalletCapabilities(HashMap); + +impl WalletCapabilities { + /// Get the capabilities of the wallet API for the specified chain ID. + pub fn get(&self, chain_id: ChainId) -> Option<&Capabilities> { + self.0.get(&U64::from(chain_id)) + } + + pub fn insert(&mut self, chain_id: ChainId, capabilities: Capabilities) { + self.0.insert(U64::from(chain_id), capabilities); + } +} + +#[derive(Debug, thiserror::Error)] +pub enum WalletError { + /// The transaction value is not 0. + /// + /// The value should be 0 to prevent draining the sequencer. + #[error("tx value not zero")] + ValueNotZero, + /// The from field is set on the transaction. + /// + /// Requests with the from field are rejected, since it is implied that it will always be the + /// sequencer. + #[error("tx from field is set")] + FromSet, + /// The nonce field is set on the transaction. + /// + /// Requests with the nonce field set are rejected, as this is managed by the sequencer. + #[error("tx nonce is set")] + NonceSet, + /// An authorization item was invalid. + /// + /// The item is invalid if it tries to delegate an account to a contract that is not + /// whitelisted. + #[error("invalid authorization address")] + InvalidAuthorization, + /// The to field of the transaction was invalid. + /// + /// The destination is invalid if: + /// + /// - There is no bytecode at the destination, or + /// - The bytecode is not an EIP-7702 delegation designator, or + /// - The delegation designator points to a contract that is not whitelisted + #[error("the destination of the transaction is not a delegated account")] + IllegalDestination, + /// The transaction request was invalid. + /// + /// This is likely an internal error, as most of the request is built by the sequencer. + #[error("invalid tx request")] + InvalidTransactionRequest, + /// An internal error occurred. + #[error("internal error")] + InternalError, +} diff --git a/crates/anvil/src/anvil.rs b/crates/anvil/src/anvil.rs index 38bbbbbd6..5e2a42f59 100644 --- a/crates/anvil/src/anvil.rs +++ b/crates/anvil/src/anvil.rs @@ -2,7 +2,8 @@ use anvil::cmd::NodeArgs; use clap::{CommandFactory, Parser, Subcommand}; -use foundry_cli::utils; +use eyre::Result; +use foundry_cli::{opts::ShellOpts, utils}; #[cfg(all(feature = "jemalloc", unix))] #[global_allocator] @@ -17,6 +18,9 @@ pub struct Anvil { #[command(subcommand)] pub cmd: Option, + + #[clap(flatten)] + pub shell: ShellOpts, } #[derive(Subcommand)] @@ -33,10 +37,18 @@ pub enum AnvilSubcommand { GenerateFigSpec, } -fn main() -> eyre::Result<()> { +fn main() { + if let Err(err) = run() { + let _ = foundry_common::sh_err!("{err:?}"); + std::process::exit(1); + } +} + +fn run() -> Result<()> { utils::load_dotenv(); let mut args = Anvil::parse(); + args.shell.shell().set(); args.node.evm_opts.resolve_rpc_alias(); if let Some(cmd) = &args.cmd { diff --git a/crates/anvil/src/cmd.rs b/crates/anvil/src/cmd.rs index 13182686a..839dae016 100644 --- a/crates/anvil/src/cmd.rs +++ b/crates/anvil/src/cmd.rs @@ -10,6 +10,7 @@ use alloy_signer_local::coins_bip39::{English, Mnemonic}; use anvil_server::ServerConfig; use clap::Parser; use core::fmt; +use foundry_common::shell; use foundry_config::{Chain, Config, FigmentProviders}; use futures::FutureExt; use rand::{rngs::StdRng, SeedableRng}; @@ -72,10 +73,6 @@ pub struct NodeArgs { #[arg(long)] pub derivation_path: Option, - /// Don't print anything on startup and don't print logs - #[arg(long)] - pub silent: bool, - /// The EVM hardfork to use. /// /// Choose the hardfork by name, e.g. `shanghai`, `paris`, `london`, etc... @@ -258,7 +255,7 @@ impl NodeArgs { .with_storage_caching(self.evm_opts.no_storage_caching) .with_server_config(self.server_config) .with_host(self.host) - .set_silent(self.silent) + .set_silent(shell::is_quiet()) .set_config_out(self.config_out) .with_chain_id(self.evm_opts.chain_id) .with_transaction_order(self.order) @@ -564,8 +561,9 @@ pub struct AnvilEvmArgs { #[arg(long, visible_alias = "no-console-log")] pub disable_console_log: bool, - /// Enable autoImpersonate on startup - #[arg(long, visible_alias = "auto-impersonate")] + /// Enables automatic impersonation on startup. This allows any transaction sender to be + /// simulated as different accounts, which is useful for testing contract behavior. + #[arg(long, visible_alias = "auto-unlock")] pub auto_impersonate: bool, /// Run an Optimism chain diff --git a/crates/anvil/src/config.rs b/crates/anvil/src/config.rs index 273dbad89..556175818 100644 --- a/crates/anvil/src/config.rs +++ b/crates/anvil/src/config.rs @@ -123,8 +123,6 @@ pub struct NodeConfig { pub port: u16, /// maximum number of transactions in a block pub max_transactions: usize, - /// don't print anything on startup - pub silent: bool, /// url of the rpc server that should be used for any rpc calls pub eth_rpc_url: Option, /// pins the block number or transaction hash for the state fork @@ -189,6 +187,8 @@ pub struct NodeConfig { pub precompile_factory: Option>, /// Enable Alphanet features. pub alphanet: bool, + /// Do not print log messages. + pub silent: bool, } impl NodeConfig { @@ -394,7 +394,7 @@ impl NodeConfig { /// random, free port by setting it to `0` #[doc(hidden)] pub fn test() -> Self { - Self { enable_tracing: true, silent: true, port: 0, ..Default::default() } + Self { enable_tracing: true, port: 0, silent: true, ..Default::default() } } /// Returns a new config which does not initialize any accounts on node startup. @@ -429,7 +429,6 @@ impl Default for NodeConfig { port: NODE_PORT, // TODO make this something dependent on block capacity max_transactions: 1_000, - silent: false, eth_rpc_url: None, fork_choice: None, account_generator: None, @@ -465,6 +464,7 @@ impl Default for NodeConfig { memory_limit: None, precompile_factory: None, alphanet: false, + silent: false, } } } @@ -732,18 +732,6 @@ impl NodeConfig { self } - /// Makes the node silent to not emit anything on stdout - #[must_use] - pub fn silent(self) -> Self { - self.set_silent(true) - } - - #[must_use] - pub fn set_silent(mut self, silent: bool) -> Self { - self.silent = silent; - self - } - /// Sets the ipc path to use /// /// Note: this is a double Option for @@ -763,7 +751,7 @@ impl NodeConfig { self } - /// Makes the node silent to not emit anything on stdout + /// Disables storage caching #[must_use] pub fn no_storage_caching(self) -> Self { self.with_storage_caching(true) @@ -921,11 +909,12 @@ impl NodeConfig { ) .expect("Failed writing json"); } + if self.silent { return; } - println!("{}", self.as_string(fork)) + let _ = sh_println!("{}", self.as_string(fork)); } /// Returns the path where the cache file should be stored @@ -968,6 +957,18 @@ impl NodeConfig { self } + /// Makes the node silent to not emit anything on stdout + #[must_use] + pub fn silent(self) -> Self { + self.set_silent(true) + } + + #[must_use] + pub fn set_silent(mut self, silent: bool) -> Self { + self.silent = silent; + self + } + /// Configures everything related to env, backend and database and returns the /// [Backend](mem::Backend) /// diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index a85862664..81990d755 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -4,8 +4,8 @@ use super::{ }; use crate::{ eth::{ - backend, backend::{ + self, db::SerializableState, mem::{MIN_CREATE_GAS, MIN_TRANSACTION_GAS}, notifications::NewBlockNotifications, @@ -23,8 +23,7 @@ use crate::{ }, Pool, }, - sign, - sign::Signer, + sign::{self, Signer}, }, filter::{EthFilter, Filters, LogsFilter}, mem::transaction_build, @@ -34,11 +33,17 @@ use crate::{ use alloy_consensus::{transaction::eip4844::TxEip4844Variant, Account, TxEnvelope}; use alloy_dyn_abi::TypedData; use alloy_eips::eip2718::Encodable2718; -use alloy_network::{eip2718::Decodable2718, BlockResponse}; +use alloy_network::{ + eip2718::Decodable2718, BlockResponse, Ethereum, NetworkWallet, TransactionBuilder, +}; use alloy_primitives::{ map::{HashMap, HashSet}, Address, Bytes, Parity, TxHash, TxKind, B256, B64, U256, U64, }; +use alloy_provider::utils::{ + eip1559_default_estimator, EIP1559_FEE_ESTIMATION_PAST_BLOCKS, + EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE, +}; use alloy_rpc_types::{ anvil::{ ForkedNetwork, Forking, Metadata, MineOptions, NodeEnvironment, NodeForkConfig, NodeInfo, @@ -65,6 +70,7 @@ use anvil_core::{ transaction_request_to_typed, PendingTransaction, ReceiptResponse, TypedTransaction, TypedTransactionRequest, }, + wallet::{WalletCapabilities, WalletError}, EthRequest, }, types::{ReorgOptions, TransactionData, Work}, @@ -82,6 +88,7 @@ use foundry_evm::{ }; use futures::channel::{mpsc::Receiver, oneshot}; use parking_lot::RwLock; +use revm::primitives::Bytecode; use std::{future::Future, sync::Arc, time::Duration}; /// The client version: `anvil/v{major}.{minor}.{patch}` @@ -449,6 +456,14 @@ impl EthApi { EthRequest::Reorg(reorg_options) => { self.anvil_reorg(reorg_options).await.to_rpc_result() } + EthRequest::WalletGetCapabilities(()) => self.get_capabilities().to_rpc_result(), + EthRequest::WalletSendTransaction(tx) => { + self.wallet_send_transaction(*tx).await.to_rpc_result() + } + EthRequest::AnvilAddCapability(addr) => self.anvil_add_capability(addr).to_rpc_result(), + EthRequest::AnvilSetExecutor(executor_pk) => { + self.anvil_set_executor(executor_pk).to_rpc_result() + } } } @@ -1682,12 +1697,12 @@ impl EthApi { // mine all the blocks for _ in 0..blocks.to::() { - self.mine_one().await; - // If we have an interval, jump forwards in time to the "next" timestamp if let Some(interval) = interval { self.backend.time().increase_time(interval); } + + self.mine_one().await; } Ok(()) @@ -2369,6 +2384,137 @@ impl EthApi { } } +// ===== impl Wallet endppoints ===== +impl EthApi { + /// Get the capabilities of the wallet. + /// + /// See also [EIP-5792][eip-5792]. + /// + /// [eip-5792]: https://eips.ethereum.org/EIPS/eip-5792 + pub fn get_capabilities(&self) -> Result { + node_info!("wallet_getCapabilities"); + Ok(self.backend.get_capabilities()) + } + + pub async fn wallet_send_transaction( + &self, + mut request: WithOtherFields, + ) -> Result { + node_info!("wallet_sendTransaction"); + + // Validate the request + // reject transactions that have a non-zero value to prevent draining the executor. + if request.value.is_some_and(|val| val > U256::ZERO) { + return Err(WalletError::ValueNotZero.into()) + } + + // reject transactions that have from set, as this will be the executor. + if request.from.is_some() { + return Err(WalletError::FromSet.into()); + } + + // reject transaction requests that have nonce set, as this is managed by the executor. + if request.nonce.is_some() { + return Err(WalletError::NonceSet.into()); + } + + let capabilities = self.backend.get_capabilities(); + let valid_delegations: &[Address] = capabilities + .get(self.chain_id()) + .map(|caps| caps.delegation.addresses.as_ref()) + .unwrap_or_default(); + + if let Some(authorizations) = &request.authorization_list { + if authorizations.iter().any(|auth| !valid_delegations.contains(&auth.address)) { + return Err(WalletError::InvalidAuthorization.into()); + } + } + + // validate the destination address + match (request.authorization_list.is_some(), request.to) { + // if this is an eip-1559 tx, ensure that it is an account that delegates to a + // whitelisted address + (false, Some(TxKind::Call(addr))) => { + let acc = self.backend.get_account(addr).await?; + + let delegated_address = acc + .code + .map(|code| match code { + Bytecode::Eip7702(c) => c.address(), + _ => Address::ZERO, + }) + .unwrap_or_default(); + + // not a whitelisted address, or not an eip-7702 bytecode + if delegated_address == Address::ZERO || + !valid_delegations.contains(&delegated_address) + { + return Err(WalletError::IllegalDestination.into()); + } + } + // if it's an eip-7702 tx, let it through + (true, _) => (), + // create tx's disallowed + _ => return Err(WalletError::IllegalDestination.into()), + } + + let wallet = self.backend.executor_wallet().ok_or(WalletError::InternalError)?; + + let from = NetworkWallet::::default_signer_address(&wallet); + + let nonce = self.get_transaction_count(from, Some(BlockId::latest())).await?; + + request.nonce = Some(nonce); + + let chain_id = self.chain_id(); + + request.chain_id = Some(chain_id); + + request.from = Some(from); + + let gas_limit_fut = self.estimate_gas(request.clone(), Some(BlockId::latest()), None); + + let fees_fut = self.fee_history( + U256::from(EIP1559_FEE_ESTIMATION_PAST_BLOCKS), + BlockNumber::Latest, + vec![EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE], + ); + + let (gas_limit, fees) = tokio::join!(gas_limit_fut, fees_fut); + + let gas_limit = gas_limit?; + let fees = fees?; + + request.gas = Some(gas_limit.to()); + + let base_fee = fees.latest_block_base_fee().unwrap_or_default(); + + let estimation = eip1559_default_estimator(base_fee, &fees.reward.unwrap_or_default()); + + request.max_fee_per_gas = Some(estimation.max_fee_per_gas); + request.max_priority_fee_per_gas = Some(estimation.max_priority_fee_per_gas); + request.gas_price = None; + + let envelope = request.build(&wallet).await.map_err(|_| WalletError::InternalError)?; + + self.send_raw_transaction(envelope.encoded_2718().into()).await + } + + /// Add an address to the delegation capability of wallet. + /// + /// This entails that the executor will now be able to sponsor transactions to this address. + pub fn anvil_add_capability(&self, address: Address) -> Result<()> { + node_info!("anvil_addCapability"); + self.backend.add_capability(address); + Ok(()) + } + + pub fn anvil_set_executor(&self, executor_pk: String) -> Result
{ + node_info!("anvil_setExecutor"); + self.backend.set_executor(executor_pk) + } +} + impl EthApi { /// Executes the future on a new blocking task. async fn on_blocking_task(&self, c: C) -> Result diff --git a/crates/anvil/src/eth/backend/db.rs b/crates/anvil/src/eth/backend/db.rs index 90eaaee05..ca3ff68fa 100644 --- a/crates/anvil/src/eth/backend/db.rs +++ b/crates/anvil/src/eth/backend/db.rs @@ -559,3 +559,57 @@ impl IntoIterator for SerializableHistoricalStates { self.0.into_iter() } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_deser_block() { + let block = r#"{ + "header": { + "parentHash": "0xceb0fe420d6f14a8eeec4319515b89acbb0bb4861cad9983d529ab4b1e4af929", + "ommersHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "beneficiary": "0x0000000000000000000000000000000000000000", + "stateRoot": "0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1", + "transactionsRoot": "0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988", + "receiptsRoot": "0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "0x0", + "number": "0x2", + "gasLimit": "0x1c9c380", + "gasUsed": "0x5208", + "timestamp": "0x66cdc823", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x342a1c58", + "blobGasUsed": "0x0", + "excessBlobGas": "0x0", + "extraData": "0x" + }, + "transactions": [ + { + "EIP1559": { + "chainId": "0x7a69", + "nonce": "0x0", + "gas": "0x5209", + "maxFeePerGas": "0x77359401", + "maxPriorityFeePerGas": "0x1", + "to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "value": "0x0", + "accessList": [], + "input": "0x", + "r": "0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0", + "s": "0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd", + "yParity": "0x0", + "hash": "0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515" + } + } + ], + "ommers": [] + } + "#; + + let _block: SerializableBlock = serde_json::from_str(block).unwrap(); + } +} diff --git a/crates/anvil/src/eth/backend/executor.rs b/crates/anvil/src/eth/backend/executor.rs index 3ceee8b04..a00afd962 100644 --- a/crates/anvil/src/eth/backend/executor.rs +++ b/crates/anvil/src/eth/backend/executor.rs @@ -8,8 +8,8 @@ use crate::{ mem::inspector::Inspector, PrecompileFactory, }; -use alloy_consensus::{Header, Receipt, ReceiptWithBloom}; -use alloy_eips::eip2718::Encodable2718; +use alloy_consensus::{constants::EMPTY_WITHDRAWALS, Receipt, ReceiptWithBloom}; +use alloy_eips::{eip2718::Encodable2718, eip7685::EMPTY_REQUESTS_HASH}; use alloy_primitives::{Bloom, BloomInput, Log, B256}; use anvil_core::eth::{ block::{Block, BlockInfo, PartialHeader}, @@ -134,7 +134,9 @@ impl TransactionExecutor<'_, DB, V> { None }; + let is_shanghai = self.cfg_env.handler_cfg.spec_id >= SpecId::SHANGHAI; let is_cancun = self.cfg_env.handler_cfg.spec_id >= SpecId::CANCUN; + let is_prague = self.cfg_env.handler_cfg.spec_id >= SpecId::PRAGUE; let excess_blob_gas = if is_cancun { self.block_env.get_blob_excess_gas() } else { None }; let mut cumulative_blob_gas_used = if is_cancun { Some(0u64) } else { None }; @@ -208,7 +210,6 @@ impl TransactionExecutor<'_, DB, V> { transactions.push(transaction.pending_transaction.transaction.clone()); } - let ommers: Vec
= Vec::new(); let receipts_root = trie::ordered_trie_root(receipts.iter().map(Encodable2718::encoded_2718)); @@ -227,12 +228,14 @@ impl TransactionExecutor<'_, DB, V> { mix_hash: Default::default(), nonce: Default::default(), base_fee, - parent_beacon_block_root: Default::default(), + parent_beacon_block_root: is_cancun.then_some(Default::default()), blob_gas_used: cumulative_blob_gas_used, excess_blob_gas, + withdrawals_root: is_shanghai.then_some(EMPTY_WITHDRAWALS), + requests_hash: is_prague.then_some(EMPTY_REQUESTS_HASH), }; - let block = Block::new(partial_header, transactions.clone(), ommers); + let block = Block::new(partial_header, transactions.clone()); let block = BlockInfo { block, transactions: transaction_infos, receipts }; ExecutedTransactions { block, included, invalid } } diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 0b7777f2d..c7ff9422a 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -36,7 +36,10 @@ use crate::{ use alloy_chains::NamedChain; use alloy_consensus::{Account, Header, Receipt, ReceiptWithBloom}; use alloy_eips::eip4844::MAX_BLOBS_PER_BLOCK; -use alloy_primitives::{keccak256, Address, Bytes, TxHash, TxKind, B256, U256, U64}; +use alloy_network::EthereumWallet; +use alloy_primitives::{ + address, hex, keccak256, utils::Unit, Address, Bytes, TxHash, TxKind, B256, U256, U64, +}; use alloy_rpc_types::{ anvil::Forking, request::TransactionRequest, @@ -56,6 +59,7 @@ use alloy_rpc_types::{ Transaction, TransactionReceipt, }; use alloy_serde::WithOtherFields; +use alloy_signer_local::PrivateKeySigner; use alloy_trie::{proof::ProofRetainer, HashBuilder, Nibbles}; use anvil_core::eth::{ block::{Block, BlockInfo}, @@ -64,6 +68,7 @@ use anvil_core::eth::{ TransactionInfo, TypedReceipt, TypedTransaction, }, utils::meets_eip155, + wallet::{Capabilities, DelegationCapability, WalletCapabilities}, }; use anvil_rpc::error::RpcError; use chrono::Datelike; @@ -111,6 +116,17 @@ pub mod storage; pub const MIN_TRANSACTION_GAS: u128 = 21000; // Gas per transaction creating a contract. pub const MIN_CREATE_GAS: u128 = 53000; +// Executor +pub const EXECUTOR: Address = address!("6634F723546eCc92277e8a2F93d4f248bf1189ea"); +pub const EXECUTOR_PK: &str = "0x502d47e1421cb9abef497096728e69f07543232b93ef24de4998e18b5fd9ba0f"; +// P256 Batch Delegation Contract: https://odyssey-explorer.ithaca.xyz/address/0x35202a6E6317F3CC3a177EeEE562D3BcDA4a6FcC +pub const P256_DELEGATION_CONTRACT: Address = address!("35202a6e6317f3cc3a177eeee562d3bcda4a6fcc"); +// Runtime code of the P256 delegation contract +pub const P256_DELEGATION_RUNTIME_CODE: &[u8] = &hex!("60806040526004361015610018575b361561001657005b005b5f3560e01c806309c5eabe146100c75780630cb6aaf1146100c257806330f6a8e5146100bd5780635fce1927146100b8578063641cdfe2146100b357806376ba882d146100ae5780638d80ff0a146100a9578063972ce4bc146100a4578063a78fc2441461009f578063a82e44e01461009a5763b34893910361000e576108e1565b6108b5565b610786565b610646565b6105ba565b610529565b6103f8565b6103a2565b61034c565b6102c0565b61020b565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff8211176100fc57604052565b6100cc565b6080810190811067ffffffffffffffff8211176100fc57604052565b60a0810190811067ffffffffffffffff8211176100fc57604052565b90601f8019910116810190811067ffffffffffffffff8211176100fc57604052565b6040519061016a608083610139565b565b67ffffffffffffffff81116100fc57601f01601f191660200190565b9291926101948261016c565b916101a26040519384610139565b8294818452818301116101be578281602093845f960137010152565b5f80fd5b9080601f830112156101be578160206101dd93359101610188565b90565b60206003198201126101be576004359067ffffffffffffffff82116101be576101dd916004016101c2565b346101be57610219366101e0565b3033036102295761001690610ae6565b636f6a1b8760e11b5f5260045ffd5b634e487b7160e01b5f52603260045260245ffd5b5f54811015610284575f8080526005919091027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630191565b610238565b8054821015610284575f52600560205f20910201905f90565b906040516102af816100e0565b602060018294805484520154910152565b346101be5760203660031901126101be576004355f548110156101be576102e69061024c565b5060ff815416600182015491610306600360ff60028401541692016102a2565b926040519215158352602083015260028110156103385760a09260209160408401528051606084015201516080820152f35b634e487b7160e01b5f52602160045260245ffd5b346101be575f3660031901126101be576020600254604051908152f35b6004359063ffffffff821682036101be57565b6064359063ffffffff821682036101be57565b6084359063ffffffff821682036101be57565b346101be5760203660031901126101be576103bb610369565b303303610229576103cb9061024c565b50805460ff19169055005b60609060231901126101be57602490565b60609060831901126101be57608490565b346101be5760803660031901126101be57610411610369565b60205f61041d366103d6565b60015461043161042c82610a0b565b600155565b60405184810191825260e086901b6001600160e01b031916602083015261046581602484015b03601f198101835282610139565b51902060ff61047660408401610a19565b161583146104fe576104b2601b925b85813591013590604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156104f9575f51306001600160a01b03909116036104ea576104df6100169161024c565b50805460ff19169055565b638baa579f60e01b5f5260045ffd5b610a27565b6104b2601c92610485565b60409060031901126101be57600490565b6044359060028210156101be57565b346101be5760803660031901126101be5761054336610509565b61054b61051a565b606435903033036102295761059192610580610587926040519461056e86610101565b60018652602086015260408501610a32565b36906105f3565b6060820152610a3e565b5f545f1981019081116105b55760405163ffffffff919091168152602090f35b0390f35b6109f7565b6100166105c6366101e0565b610ae6565b60409060231901126101be57604051906105e4826100e0565b60243582526044356020830152565b91908260409103126101be5760405161060b816100e0565b6020808294803584520135910152565b6084359081151582036101be57565b60a4359081151582036101be57565b359081151582036101be57565b346101be5760a03660031901126101be5760043567ffffffffffffffff81116101be576106779036906004016101c2565b610680366105cb565b61068861037c565b61069061061b565b906002546106a56106a082610a0b565b600255565b6040516106bb8161045788602083019586610b6a565b51902091610747575b6106d06106d69161024c565b50610b7b565b906106e86106e48351151590565b1590565b610738576020820151801515908161072e575b5061071f576107129260606106e493015191610ce3565b6104ea5761001690610ae6565b632572e3a960e01b5f5260045ffd5b905042115f6106fb565b637dd286d760e11b5f5260045ffd5b905f61077361045761076760209460405192839187830160209181520190565b60405191828092610b58565b039060025afa156104f9575f51906106c4565b346101be5760e03660031901126101be576107a036610509565b6107a861051a565b6064359060205f6107b8366103e7565b6001546107c761042c82610a0b565b60408051808601928352883560208401528589013591830191909152606082018790526107f78160808401610457565b51902060ff61080860408401610a19565b161583146108aa5760408051918252601b602083015282359082015290830135606082015280608081015b838052039060015afa156104f9575f51306001600160a01b03909116036104ea5761087a926105806105879261086761015b565b6001815294602086015260408501610a32565b6105b161089361088a5f54610ad8565b63ffffffff1690565b60405163ffffffff90911681529081906020820190565b610833601c92610485565b346101be575f3660031901126101be576020600154604051908152f35b359061ffff821682036101be57565b346101be5760c03660031901126101be5760043567ffffffffffffffff81116101be576109129036906004016101c2565b61091b366105cb565b906064359167ffffffffffffffff83116101be5760a060031984360301126101be576040516109498161011d565b836004013567ffffffffffffffff81116101be5761096d90600436918701016101c2565b8152602484013567ffffffffffffffff81116101be57840193366023860112156101be5760846109db916109ae610016973690602460048201359101610188565b60208501526109bf604482016108d2565b60408501526109d0606482016108d2565b606085015201610639565b60808201526109e861038f565b916109f161062a565b93610bc3565b634e487b7160e01b5f52601160045260245ffd5b5f1981146105b55760010190565b3560ff811681036101be5790565b6040513d5f823e3d90fd5b60028210156103385752565b5f54680100000000000000008110156100fc57806001610a6192015f555f610289565b610ac557610a7e82511515829060ff801983541691151516179055565b6020820151600182015560028101604083015160028110156103385761016a9360039260609260ff8019835416911617905501519101906020600191805184550151910155565b634e487b7160e01b5f525f60045260245ffd5b5f198101919082116105b557565b80519060205b828110610af857505050565b808201805160f81c600182015160601c91601581015160358201519384915f9493845f14610b4257505050506001146101be575b15610b3a5701605501610aec565b3d5f803e3d5ffd5b5f95508594506055019130811502175af1610b2c565b805191908290602001825e015f815290565b6020906101dd939281520190610b58565b90604051610b8881610101565b6060610bbe6003839560ff8154161515855260018101546020860152610bb860ff60028301541660408701610a32565b016102a2565b910152565b93909192600254610bd66106a082610a0b565b604051610bec8161045789602083019586610b6a565b51902091610c50575b6106d0610c019161024c565b91610c0f6106e48451151590565b6107385760208301518015159081610c46575b5061071f57610c399360606106e494015192610e0d565b6104ea5761016a90610ae6565b905042115f610c22565b905f610c7061045761076760209460405192839187830160209181520190565b039060025afa156104f9575f5190610bf5565b3d15610cad573d90610c948261016c565b91610ca26040519384610139565b82523d5f602084013e565b606090565b8051601f101561028457603f0190565b8051602010156102845760400190565b908151811015610284570160200190565b5f9291839260208251920151906020815191015191604051936020850195865260408501526060840152608083015260a082015260a08152610d2660c082610139565b519060145afa610d34610c83565b81610d74575b81610d43575090565b600160f81b91506001600160f81b031990610d6f90610d6190610cb2565b516001600160f81b03191690565b161490565b80516020149150610d3a565b60405190610d8f604083610139565b6015825274113a3cb832911d113bb2b130baba34371733b2ba1160591b6020830152565b9061016a6001610de3936040519485916c1131b430b63632b733b2911d1160991b6020840152602d830190610b58565b601160f91b815203601e19810185520183610139565b610e069060209392610b58565b9081520190565b92919281516025815110908115610f0a575b50610ef957610e2c610d80565b90610e596106e460208501938451610e53610e4c606089015161ffff1690565b61ffff1690565b91610f9b565b610f01576106e4610e8d610e88610457610e83610ea1956040519283916020830160209181520190565b611012565b610db3565b8351610e53610e4c604088015161ffff1690565b610ef9575f610eb96020925160405191828092610b58565b039060025afa156104f9575f610ee360209261076783519151610457604051938492888401610df9565b039060025afa156104f9576101dd915f51610ce3565b505050505f90565b50505050505f90565b610f2b9150610f1e610d616106e492610cc2565b6080850151151590610f31565b5f610e1f565b906001600160f81b0319600160f81b831601610f955780610f85575b610f8057601f60fb1b600160fb1b821601610f69575b50600190565b600160fc1b90811614610f7c575f610f63565b5f90565b505f90565b50600160fa1b8181161415610f4d565b50505f90565b80519282515f5b858110610fb457505050505050600190565b8083018084116105b5578281101561100757610fe56001600160f81b0319610fdc8488610cd2565b51169187610cd2565b516001600160f81b03191603610ffd57600101610fa2565b5050505050505f90565b505050505050505f90565b80516060929181611021575050565b9092506003600284010460021b604051937f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f603f52602085019282860191602083019460208284010190600460038351955f85525b0191603f8351818160121c16515f538181600c1c1651600153818160061c165160025316516003535f5181520190878210156110db5760049060039061109a565b5095505f93600393604092520160405206600204809303613d3d60f01b81525203825256fea26469706673582212200ba93b78f286a25ece47e9403c47be9862f9b8b70ba1a95098667b90c47308b064736f6c634300081a0033"); +// Experimental ERC20 +pub const EXP_ERC20_CONTRACT: Address = address!("238c8CD93ee9F8c7Edf395548eF60c0d2e46665E"); +// Runtime code of the experimental ERC20 contract +pub const EXP_ERC20_RUNTIME_CODE: &[u8] = &hex!("60806040526004361015610010575b005b5f3560e01c806306fdde03146106f7578063095ea7b31461068c57806318160ddd1461066757806323b872dd146105a15780632bb7c5951461050e578063313ce567146104f35780633644e5151461045557806340c10f191461043057806370a08231146103fe5780637ecebe00146103cc57806395d89b4114610366578063a9059cbb146102ea578063ad0c8fdd146102ad578063d505accf146100fb5763dd62ed3e0361000e57346100f75760403660031901126100f7576100d261075c565b6100da610772565b602052637f5e9f20600c525f5260206034600c2054604051908152f35b5f80fd5b346100f75760e03660031901126100f75761011461075c565b61011c610772565b6084359160643560443560ff851685036100f757610138610788565b60208101906e04578706572696d656e74455243323608c1b8252519020908242116102a0576040519360018060a01b03169460018060a01b03169565383775081901600e52855f5260c06020600c20958654957f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8252602082019586528660408301967fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc688528b6060850198468a528c608087019330855260a08820602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9885252528688525260a082015220604e526042602c205f5260ff1660205260a43560405260c43560605260208060805f60015afa93853d5103610293577f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92594602094019055856303faf4f960a51b176040526034602c2055a3005b63ddafbaef5f526004601cfd5b631a15a3cc5f526004601cfd5b5f3660031901126100f7576103e834023481046103e814341517156102d65761000e90336107ac565b634e487b7160e01b5f52601160045260245ffd5b346100f75760403660031901126100f75761030361075c565b602435906387a211a2600c52335f526020600c2080548084116103595783900390555f526020600c20818154019055602052600c5160601c335f51602061080d5f395f51905f52602080a3602060405160018152f35b63f4d678b85f526004601cfd5b346100f7575f3660031901126100f757604051604081019080821067ffffffffffffffff8311176103b8576103b491604052600381526204558560ec1b602082015260405191829182610732565b0390f35b634e487b7160e01b5f52604160045260245ffd5b346100f75760203660031901126100f7576103e561075c565b6338377508600c525f52602080600c2054604051908152f35b346100f75760203660031901126100f75761041761075c565b6387a211a2600c525f52602080600c2054604051908152f35b346100f75760403660031901126100f75761000e61044c61075c565b602435906107ac565b346100f7575f3660031901126100f757602060a0610471610788565b828101906e04578706572696d656e74455243323608c1b8252519020604051907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8252838201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604082015246606082015230608082015220604051908152f35b346100f7575f3660031901126100f757602060405160128152f35b346100f75760203660031901126100f7576004356387a211a2600c52335f526020600c2090815490818111610359575f80806103e88487839688039055806805345cdf77eb68f44c54036805345cdf77eb68f44c5580835282335f51602061080d5f395f51905f52602083a304818115610598575b3390f11561058d57005b6040513d5f823e3d90fd5b506108fc610583565b346100f75760603660031901126100f7576105ba61075c565b6105c2610772565b604435908260601b33602052637f5e9f208117600c526034600c20908154918219610643575b506387a211a2915017600c526020600c2080548084116103595783900390555f526020600c20818154019055602052600c5160601c9060018060a01b03165f51602061080d5f395f51905f52602080a3602060405160018152f35b82851161065a57846387a211a293039055856105e8565b6313be252b5f526004601cfd5b346100f7575f3660031901126100f75760206805345cdf77eb68f44c54604051908152f35b346100f75760403660031901126100f7576106a561075c565b60243590602052637f5e9f20600c52335f52806034600c20555f52602c5160601c337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa3602060405160018152f35b346100f7575f3660031901126100f7576103b4610712610788565b6e04578706572696d656e74455243323608c1b6020820152604051918291825b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b03821682036100f757565b602435906001600160a01b03821682036100f757565b604051906040820182811067ffffffffffffffff8211176103b857604052600f8252565b6805345cdf77eb68f44c548281019081106107ff576805345cdf77eb68f44c556387a211a2600c525f526020600c20818154019055602052600c5160601c5f5f51602061080d5f395f51905f52602080a3565b63e5cfe9575f526004601cfdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220fbe302881d9891005ba1448ba48547cc1cb17dea1a5c4011dfcb035de325bb1d64736f6c634300081b0033"); pub type State = foundry_evm::utils::StateChangeset; @@ -186,6 +202,9 @@ pub struct Backend { precompile_factory: Option>, /// Prevent race conditions during mining mining: Arc>, + // === wallet === // + capabilities: Arc>, + executor_wallet: Arc>>, } impl Backend { @@ -211,8 +230,10 @@ impl Backend { trace!(target: "backend", "using forked blockchain at {}", fork.block_number()); Blockchain::forked(fork.block_number(), fork.block_hash(), fork.total_difficulty()) } else { + let env = env.read(); Blockchain::new( - &env.read(), + &env, + env.handler_cfg.spec_id, fees.is_eip1559().then(|| fees.base_fee()), genesis.timestamp, ) @@ -244,6 +265,43 @@ impl Backend { (cfg.slots_in_an_epoch, cfg.precompile_factory.clone()) }; + let (capabilities, executor_wallet) = if alphanet { + // Insert account that sponsors the delegated txs. And deploy P256 delegation contract. + let mut db = db.write().await; + + let _ = db.set_code( + P256_DELEGATION_CONTRACT, + Bytes::from_static(P256_DELEGATION_RUNTIME_CODE), + ); + + // Insert EXP ERC20 contract + let _ = db.set_code(EXP_ERC20_CONTRACT, Bytes::from_static(EXP_ERC20_RUNTIME_CODE)); + + let init_balance = Unit::ETHER.wei().saturating_mul(U256::from(10_000)); // 10K ETH + + // Add ETH + let _ = db.set_balance(EXP_ERC20_CONTRACT, init_balance); + let _ = db.set_balance(EXECUTOR, init_balance); + + let mut capabilities = WalletCapabilities::default(); + + let chain_id = env.read().cfg.chain_id; + capabilities.insert( + chain_id, + Capabilities { + delegation: DelegationCapability { addresses: vec![P256_DELEGATION_CONTRACT] }, + }, + ); + + let signer: PrivateKeySigner = EXECUTOR_PK.parse().unwrap(); + + let executor_wallet = EthereumWallet::new(signer); + + (capabilities, Some(executor_wallet)) + } else { + (WalletCapabilities::default(), None) + }; + let backend = Self { db, blockchain, @@ -265,6 +323,8 @@ impl Backend { slots_in_an_epoch, precompile_factory, mining: Arc::new(tokio::sync::Mutex::new(())), + capabilities: Arc::new(RwLock::new(capabilities)), + executor_wallet: Arc::new(RwLock::new(executor_wallet)), }; if let Some(interval_block_time) = automine_block_time { @@ -283,11 +343,45 @@ impl Backend { Ok(()) } + /// Get the capabilities of the wallet. + /// + /// Currently the only capability is [`DelegationCapability`]. + /// + /// [`DelegationCapability`]: anvil_core::eth::wallet::DelegationCapability + pub(crate) fn get_capabilities(&self) -> WalletCapabilities { + self.capabilities.read().clone() + } + /// Updates memory limits that should be more strict when auto-mine is enabled pub(crate) fn update_interval_mine_block_time(&self, block_time: Duration) { self.states.write().update_interval_mine_block_time(block_time) } + pub(crate) fn executor_wallet(&self) -> Option { + self.executor_wallet.read().clone() + } + + /// Adds an address to the [`DelegationCapability`] of the wallet. + pub(crate) fn add_capability(&self, address: Address) { + let chain_id = self.env.read().cfg.chain_id; + let mut capabilities = self.capabilities.write(); + let mut capability = capabilities.get(chain_id).cloned().unwrap_or_default(); + capability.delegation.addresses.push(address); + capabilities.insert(chain_id, capability); + } + + pub(crate) fn set_executor(&self, executor_pk: String) -> Result { + let signer: PrivateKeySigner = + executor_pk.parse().map_err(|_| RpcError::invalid_params("Invalid private key"))?; + + let executor = signer.address(); + let wallet = EthereumWallet::new(signer); + + *self.executor_wallet.write() = Some(wallet); + + Ok(executor) + } + /// Applies the configured genesis settings /// /// This will fund, create the genesis accounts @@ -815,19 +909,27 @@ impl Backend { // Set the current best block number. // Defaults to block number for compatibility with existing state files. + let fork_num_and_hash = self.get_fork().map(|f| (f.block_number(), f.block_hash())); - let best_number = state.best_block_number.unwrap_or(block.number.to::()); - self.blockchain.storage.write().best_number = best_number; - - // Set the current best block hash; - let best_hash = - self.blockchain.storage.read().hash(best_number.into()).ok_or_else(|| { - BlockchainError::RpcError(RpcError::internal_error_with(format!( - "Best hash not found for best number {best_number}", - ))) - })?; - - self.blockchain.storage.write().best_hash = best_hash; + if let Some((number, hash)) = fork_num_and_hash { + // If loading state file on a fork, set best number to the fork block number. + // Ref: https://github.com/foundry-rs/foundry/pull/9215#issue-2618681838 + self.blockchain.storage.write().best_number = U64::from(number); + self.blockchain.storage.write().best_hash = hash; + } else { + let best_number = state.best_block_number.unwrap_or(block.number.to::()); + self.blockchain.storage.write().best_number = best_number; + + // Set the current best block hash; + let best_hash = + self.blockchain.storage.read().hash(best_number.into()).ok_or_else(|| { + BlockchainError::RpcError(RpcError::internal_error_with(format!( + "Best hash not found for best number {best_number}", + ))) + })?; + + self.blockchain.storage.write().best_hash = best_hash; + } } if !self.db.write().await.load_state(state.clone())? { @@ -1006,8 +1108,17 @@ impl Backend { env.cfg.disable_base_fee = true; } + let block_number = + self.blockchain.storage.read().best_number.saturating_add(U64::from(1)); + // increase block number for this block - env.block.number = env.block.number.saturating_add(U256::from(1)); + if is_arbitrum(env.cfg.chain_id) { + // Temporary set `env.block.number` to `block_number` for Arbitrum chains. + env.block.number = block_number.to(); + } else { + env.block.number = env.block.number.saturating_add(U256::from(1)); + } + env.block.basefee = U256::from(current_base_fee); env.block.blob_excess_gas_and_price = current_excess_blob_gas_and_price; @@ -1057,9 +1168,7 @@ impl Backend { let ExecutedTransactions { block, included, invalid } = executed_tx; let BlockInfo { block, transactions, receipts } = block; - let mut storage = self.blockchain.storage.write(); let header = block.header.clone(); - let block_number = storage.best_number.saturating_add(U64::from(1)); trace!( target: "backend", @@ -1068,7 +1177,7 @@ impl Backend { transactions.len(), transactions.iter().map(|tx| tx.transaction_hash).collect::>() ); - + let mut storage = self.blockchain.storage.write(); // update block metadata storage.best_number = block_number; storage.best_hash = block_hash; @@ -1331,13 +1440,20 @@ impl Backend { block_request: Option, opts: GethDebugTracingCallOptions, ) -> Result { - let GethDebugTracingCallOptions { tracing_options, block_overrides: _, state_overrides: _ } = + let GethDebugTracingCallOptions { tracing_options, block_overrides: _, state_overrides } = opts; let GethDebugTracingOptions { config, tracer, tracer_config, .. } = tracing_options; self.with_database_at(block_request, |state, block| { let block_number = block.number; + let state = if let Some(overrides) = state_overrides { + Box::new(state::apply_state_override(overrides, state)?) + as Box + } else { + state + }; + if let Some(tracer) = tracer { return match tracer { GethDebugTracerType::BuiltInTracer(tracer) => match tracer { @@ -1769,12 +1885,12 @@ impl Backend { gas_limit, gas_used, timestamp, - requests_root, + requests_hash, extra_data, mix_hash, nonce, base_fee_per_gas, - withdrawals_root: _, + withdrawals_root, blob_gas_used, excess_blob_gas, parent_beacon_block_root, @@ -1800,32 +1916,24 @@ impl Backend { mix_hash: Some(mix_hash), nonce: Some(nonce), base_fee_per_gas, - withdrawals_root: None, + withdrawals_root, blob_gas_used, excess_blob_gas, parent_beacon_block_root, - requests_root, + requests_hash, }, size: Some(size), transactions: alloy_rpc_types::BlockTransactions::Hashes( transactions.into_iter().map(|tx| tx.hash()).collect(), ), uncles: vec![], - withdrawals: None, + withdrawals: withdrawals_root.map(|_| Default::default()), }; let mut block = WithOtherFields::new(block); // If Arbitrum, apply chain specifics to converted block. - if let Ok( - NamedChain::Arbitrum | - NamedChain::ArbitrumGoerli | - NamedChain::ArbitrumNova | - NamedChain::ArbitrumTestnet, - ) = NamedChain::try_from(self.env.read().env.cfg.chain_id) - { - // Block number is the best number. - block.header.number = self.best_number(); + if is_arbitrum(self.env.read().cfg.chain_id) { // Set `l1BlockNumber` field. block.other.insert("l1BlockNumber".to_string(), number.into()); } @@ -2324,7 +2432,6 @@ impl Backend { block_hash: Some(block_hash), from: info.from, to: info.to, - state_root: Some(block.header.state_root), blob_gas_price: Some(blob_gas_price), blob_gas_used: blob_gas_used.map(|g| g as u128), authorization_list: None, @@ -2862,3 +2969,13 @@ pub fn prove_storage(storage: &HashMap, keys: &[B256]) -> Vec bool { + matches!( + NamedChain::try_from(chain_id), + Ok(NamedChain::Arbitrum | + NamedChain::ArbitrumTestnet | + NamedChain::ArbitrumGoerli | + NamedChain::ArbitrumNova) + ) +} diff --git a/crates/anvil/src/eth/backend/mem/storage.rs b/crates/anvil/src/eth/backend/mem/storage.rs index 942ce5a9d..d5a72fccb 100644 --- a/crates/anvil/src/eth/backend/mem/storage.rs +++ b/crates/anvil/src/eth/backend/mem/storage.rs @@ -10,6 +10,8 @@ use crate::eth::{ error::BlockchainError, pool::transactions::PoolTransaction, }; +use alloy_consensus::constants::EMPTY_WITHDRAWALS; +use alloy_eips::eip7685::EMPTY_REQUESTS_HASH; use alloy_primitives::{ map::{B256HashMap, HashMap}, Bytes, B256, U256, U64, @@ -38,6 +40,7 @@ use foundry_evm::{ }, }; use parking_lot::RwLock; +use revm::primitives::SpecId; use std::{collections::VecDeque, fmt, sync::Arc, time::Duration}; // use yansi::Paint; @@ -262,7 +265,11 @@ pub struct BlockchainStorage { impl BlockchainStorage { /// Creates a new storage with a genesis block - pub fn new(env: &Env, base_fee: Option, timestamp: u64) -> Self { + pub fn new(env: &Env, spec_id: SpecId, base_fee: Option, timestamp: u64) -> Self { + let is_shanghai = spec_id >= SpecId::SHANGHAI; + let is_cancun = spec_id >= SpecId::CANCUN; + let is_prague = spec_id >= SpecId::PRAGUE; + // create a dummy genesis block let partial_header = PartialHeader { timestamp, @@ -272,9 +279,13 @@ impl BlockchainStorage { difficulty: env.block.difficulty, blob_gas_used: env.block.blob_excess_gas_and_price.as_ref().map(|_| 0), excess_blob_gas: env.block.get_blob_excess_gas(), + + parent_beacon_block_root: is_cancun.then_some(Default::default()), + withdrawals_root: is_shanghai.then_some(EMPTY_WITHDRAWALS), + requests_hash: is_prague.then_some(EMPTY_REQUESTS_HASH), ..Default::default() }; - let block = Block::new::(partial_header, vec![], vec![]); + let block = Block::new::(partial_header, vec![]); let genesis_hash = block.header.hash_slow(); let best_hash = genesis_hash; let best_number: U64 = U64::from(0u64); @@ -423,8 +434,12 @@ pub struct Blockchain { impl Blockchain { /// Creates a new storage with a genesis block - pub fn new(env: &Env, base_fee: Option, timestamp: u64) -> Self { - Self { storage: Arc::new(RwLock::new(BlockchainStorage::new(env, base_fee, timestamp))) } + pub fn new(env: &Env, spec_id: SpecId, base_fee: Option, timestamp: u64) -> Self { + Self { + storage: Arc::new(RwLock::new(BlockchainStorage::new( + env, spec_id, base_fee, timestamp, + ))), + } } pub fn forked(block_number: u64, block_hash: B256, total_difficulty: U256) -> Self { @@ -693,11 +708,8 @@ mod tests { let bytes_first = &mut &hex::decode("f86b02843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba00eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5aea03a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18").unwrap()[..]; let tx: MaybeImpersonatedTransaction = TypedTransaction::decode(&mut &bytes_first[..]).unwrap().into(); - let block = Block::new::( - partial_header.clone(), - vec![tx.clone()], - vec![], - ); + let block = + Block::new::(partial_header.clone(), vec![tx.clone()]); let block_hash = block.header.hash_slow(); dump_storage.blocks.insert(block_hash, block); diff --git a/crates/anvil/src/eth/backend/time.rs b/crates/anvil/src/eth/backend/time.rs index 0822baa04..3ae9524f0 100644 --- a/crates/anvil/src/eth/backend/time.rs +++ b/crates/anvil/src/eth/backend/time.rs @@ -70,9 +70,9 @@ impl TimeManager { /// Fails if it's before (or at the same time) the last timestamp pub fn set_next_block_timestamp(&self, timestamp: u64) -> Result<(), BlockchainError> { trace!(target: "time", "override next timestamp {}", timestamp); - if timestamp <= *self.last_timestamp.read() { + if timestamp < *self.last_timestamp.read() { return Err(BlockchainError::TimestampError(format!( - "{timestamp} is lower than or equal to previous block's timestamp" + "{timestamp} is lower than previous block's timestamp" ))) } self.next_exact_timestamp.write().replace(timestamp); @@ -112,7 +112,7 @@ impl TimeManager { (current.saturating_add(self.offset()) as u64, false) }; // Ensures that the timestamp is always increasing - if next_timestamp <= last_timestamp { + if next_timestamp < last_timestamp { next_timestamp = last_timestamp + 1; } let next_offset = update_offset.then_some((next_timestamp as i128) - current); diff --git a/crates/anvil/src/eth/error.rs b/crates/anvil/src/eth/error.rs index 31d0521bb..0c478ee06 100644 --- a/crates/anvil/src/eth/error.rs +++ b/crates/anvil/src/eth/error.rs @@ -5,6 +5,7 @@ use alloy_primitives::{Bytes, SignatureError}; use alloy_rpc_types::BlockNumberOrTag; use alloy_signer::Error as SignerError; use alloy_transport::TransportError; +use anvil_core::eth::wallet::WalletError; use anvil_rpc::{ error::{ErrorCode, RpcError}, response::ResponseResult, @@ -119,6 +120,26 @@ where } } +impl From for BlockchainError { + fn from(value: WalletError) -> Self { + match value { + WalletError::ValueNotZero => Self::Message("tx value not zero".to_string()), + WalletError::FromSet => Self::Message("tx from field is set".to_string()), + WalletError::NonceSet => Self::Message("tx nonce is set".to_string()), + WalletError::InvalidAuthorization => { + Self::Message("invalid authorization address".to_string()) + } + WalletError::IllegalDestination => Self::Message( + "the destination of the transaction is not a delegated account".to_string(), + ), + WalletError::InternalError => Self::Message("internal error".to_string()), + WalletError::InvalidTransactionRequest => { + Self::Message("invalid tx request".to_string()) + } + } + } +} + /// Errors that can occur in the transaction pool #[derive(Debug, thiserror::Error)] pub enum PoolError { @@ -273,7 +294,6 @@ impl From for InvalidTransactionError { Self::AuthorizationListNotSupported } InvalidTransaction::AuthorizationListInvalidFields | - InvalidTransaction::InvalidAuthorizationList(_) | InvalidTransaction::OptimismError(_) | InvalidTransaction::EofCrateShouldHaveToAddress | InvalidTransaction::EmptyAuthorizationList => Self::Revm(err), diff --git a/crates/anvil/src/hardfork.rs b/crates/anvil/src/hardfork.rs index c8d2fdebc..2aedb7986 100644 --- a/crates/anvil/src/hardfork.rs +++ b/crates/anvil/src/hardfork.rs @@ -135,7 +135,8 @@ impl From for SpecId { EthereumHardfork::Cancun | EthereumHardfork::Latest => Self::CANCUN, EthereumHardfork::Prague => Self::PRAGUE, // TODO: switch to latest after activation - EthereumHardfork::PragueEOF => Self::PRAGUE_EOF, + // EOF is included in OSAKA from Revm 16.0.0 + EthereumHardfork::PragueEOF => Self::OSAKA, } } } diff --git a/crates/anvil/src/lib.rs b/crates/anvil/src/lib.rs index ee66caa67..4fc0621c8 100644 --- a/crates/anvil/src/lib.rs +++ b/crates/anvil/src/lib.rs @@ -1,9 +1,6 @@ #![doc = include_str!("../README.md")] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -#[macro_use] -extern crate tracing; - use crate::{ eth::{ backend::{info::StorageInfo, mem}, @@ -74,6 +71,12 @@ mod tasks; #[cfg(feature = "cmd")] pub mod cmd; +#[macro_use] +extern crate foundry_common; + +#[macro_use] +extern crate tracing; + /// Creates the node and runs the server. /// /// Returns the [EthApi] that can be used to interact with the node and the [JoinHandle] of the @@ -294,9 +297,9 @@ impl NodeHandle { self.config.print(fork); if !self.config.silent { if let Some(ipc_path) = self.ipc_path() { - println!("IPC path: {ipc_path}"); + let _ = sh_println!("IPC path: {ipc_path}"); } - println!( + let _ = sh_println!( "Listening on {}", self.addresses .iter() diff --git a/crates/anvil/test-data/state-dump-legacy-stress.json b/crates/anvil/test-data/state-dump-legacy-stress.json index dff50a670..50df9e039 100644 --- a/crates/anvil/test-data/state-dump-legacy-stress.json +++ b/crates/anvil/test-data/state-dump-legacy-stress.json @@ -1 +1 @@ -{"block":{"number":"0x5","coinbase":"0x0000000000000000000000000000000000000000","timestamp":"0x66b200cb","gas_limit":"0x1c9c380","basefee":"0x12e09c7a","difficulty":"0x0","prevrandao":"0xe7ef87fc7c2090741a6749a087e4ca8092cb4d07136008799e4ebeac3b69e34a","blob_excess_gas_and_price":{"excess_blob_gas":0,"blob_gasprice":1}},"accounts":{"0x0000000000000000000000000000000000000000":{"nonce":0,"balance":"0x1088aa62285a00","code":"0x","storage":{}},"0x108f53faf774d7c4c56f5bce9ca6e605ce8aeadd":{"nonce":1,"balance":"0x0","code":"0x6080604052600080357fffffffff0000000000000000000000000000000000000000000000000000000016905060008160e01c610251565b60006379ba509782101561015e5781631627540c811461009857632a952b2d81146100b457633659cfe681146100d0576350c946fe81146100ec576353a47bb781146101085763625ca21c81146101245763718fe928811461014057610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc91505b5061024c565b816379ba509781146101a657638da5cb5b81146101c25763aaf10f4281146101de5763c7f62cda81146101fa5763daa250be81146102165763deba1b9881146102325761024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b738138ef7cf908021d117e542120b7a39065016107915061024a565b738138ef7cf908021d117e542120b7a3906501610791505b505b919050565b61025a81610037565b915050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102ce57816040517fc2a825f50000000000000000000000000000000000000000000000000000000081526004016102c5919061032f565b60405180910390fd5b3660008037600080366000845af43d6000803e80600081146102ef573d6000f35b3d6000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610329816102f4565b82525050565b60006020820190506103446000830184610320565b9291505056fea264697066735822122017a4b7fdaaab3897a7b47abaed8d2ee92d558883d3bb2a8454f9601b2ab2c3db64736f6c63430008150033","storage":{}},"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x19ba1fac55eea44d12a01372a8eb0c2ebbf9ca21":{"nonce":1,"balance":"0x21e19df7c2963f0ac6b","code":"0x","storage":{}},"0x19c6ab860dbe2bc433574193a4409770a8748bf6":{"nonce":1,"balance":"0x21e19df8da6b7bdc410","code":"0x","storage":{}},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x40567ec443c1d1872af5155755ac3803cc3fe61e":{"nonce":1,"balance":"0x21e19da82562f921b40","code":"0x","storage":{}},"0x47d08dad17ccb558b3ea74b1a0e73a9cc804a9dc":{"nonce":1,"balance":"0x0","code":"0x608060405234801561001057600080fd5b50600436106100885760003560e01c806379ba50971161005b57806379ba5097146100ed5780638da5cb5b146100f7578063aaf10f4214610115578063c7f62cda1461013357610088565b80631627540c1461008d5780633659cfe6146100a957806353a47bb7146100c5578063718fe928146100e3575b600080fd5b6100a760048036038101906100a29190610d25565b61014f565b005b6100c360048036038101906100be9190610d25565b6102d0565b005b6100cd6102e4565b6040516100da9190610d61565b60405180910390f35b6100eb610317565b005b6100f56103fe565b005b6100ff61058b565b60405161010c9190610d61565b60405180910390f35b61011d6105be565b60405161012a9190610d61565b60405180910390f35b61014d60048036038101906101489190610d25565b6105f1565b005b61015761084c565b600061016161081b565b9050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101c9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610252576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22826040516102c49190610d61565b60405180910390a15050565b6102d861084c565b6102e1816108c5565b50565b60006102ee61081b565b60010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600061032161081b565b90503373ffffffffffffffffffffffffffffffffffffffff168160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103b757336040517fa0e5a0d70000000000000000000000000000000000000000000000000000000081526004016103ae9190610d61565b60405180910390fd5b60008160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600061040861081b565b905060008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104a357336040517fa0e5a0d700000000000000000000000000000000000000000000000000000000815260040161049a9190610d61565b60405180910390fd5b7fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c8260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16826040516104f8929190610d7c565b60405180910390a1808260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b600061059561081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105c8610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105fb610b05565b905060018160000160146101000a81548160ff02191690831515021790555060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050828260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008373ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16633659cfe6846040516024016106cc9190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161071b9190610e16565b600060405180830381855af49150503d8060008114610756576040519150601f19603f3d011682016040523d82523d6000602084013e61075b565b606091505b505090508015806107c357508173ffffffffffffffffffffffffffffffffffffffff16610786610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b156107fa576040517fa1cfa5a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360000160146101000a81548160ff0219169083151502179055600080fd5b60008060405160200161082d90610eb0565b6040516020818303038152906040528051906020012090508091505090565b610854610b36565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108c357336040517f8e4a23d60000000000000000000000000000000000000000000000000000000081526004016108ba9190610d61565b60405180910390fd5b565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61093481610b69565b61097557806040517f8a8b41ec00000000000000000000000000000000000000000000000000000000815260040161096c9190610d61565b60405180910390fd5b600061097f610b05565b90508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610a0a576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000160149054906101000a900460ff16158015610a2e5750610a2d82610b7c565b5b15610a7057816040517f15504301000000000000000000000000000000000000000000000000000000008152600401610a679190610d61565b60405180910390fd5b818160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503073ffffffffffffffffffffffffffffffffffffffff167f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c783604051610af99190610d61565b60405180910390a25050565b600080604051602001610b1790610f42565b6040516020818303038152906040528051906020012090508091505090565b6000610b4061081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080823b905060008111915050919050565b60008060003073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1663c7f62cda86604051602401610bc59190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c149190610e16565b600060405180830381855af49150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509150915081158015610cb9575063a1cfa5a860e01b604051602001610c7a9190610faf565b6040516020818303038152906040528051906020012081604051602001610ca19190610e16565b60405160208183030381529060405280519060200120145b92505050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cf282610cc7565b9050919050565b610d0281610ce7565b8114610d0d57600080fd5b50565b600081359050610d1f81610cf9565b92915050565b600060208284031215610d3b57610d3a610cc2565b5b6000610d4984828501610d10565b91505092915050565b610d5b81610ce7565b82525050565b6000602082019050610d766000830184610d52565b92915050565b6000604082019050610d916000830185610d52565b610d9e6020830184610d52565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015610dd9578082015181840152602081019050610dbe565b60008484015250505050565b6000610df082610da5565b610dfa8185610db0565b9350610e0a818560208601610dbb565b80840191505092915050565b6000610e228284610de5565b915081905092915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b6000610e9a602383610e2d565b9150610ea582610e3e565b604082019050919050565b60006020820190508181036000830152610ec981610e8d565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b6000610f2c602183610e2d565b9150610f3782610ed0565b604082019050919050565b60006020820190508181036000830152610f5b81610f1f565b9050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610fa9610fa482610f62565b610f8e565b82525050565b6000610fbb8284610f98565b6004820191508190509291505056fea264697066735822122023a7c33d7b91dce35ffbcf8837693364ab22a3905d0fc00016833e5fac45ca2f64736f6c63430008110033","storage":{"0x5c7865864a2a990d80b5bb5c40e7b73a029960dc711fbb56120dfab976e92ea3":"0x0"}},"0x4e59b44847b379578588920ca78fbf26c0b4956c":{"nonce":2,"balance":"0x0","code":"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3","storage":{}},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x8138ef7cf908021d117e542120b7a39065016107":{"nonce":1,"balance":"0x0","code":"0x608060405234801561001057600080fd5b50600436106100575760003560e01c80632a952b2d1461005c57806350c946fe14610085578063625ca21c146100a5578063daa250be146100c6578063deba1b98146100d9575b600080fd5b61006f61006a366004613a63565b6100ec565b60405161007c9190613a7c565b60405180910390f35b610098610093366004613a63565b61011c565b60405161007c9190613b21565b6100b86100b3366004613c92565b610276565b60405190815260200161007c565b61006f6100d4366004613d5f565b6102bb565b6100b86100e7366004613c92565b6102d6565b6100f46139e4565b6040805160008082526020820190815281830190925261011691849190610310565b92915050565b6101416040805160608101909152806000815260200160608152602001606081525090565b61014a82610ab6565b60408051606081019091528154909190829060ff16600981111561017057610170613aa7565b600981111561018157610181613aa7565b815260200160018201805461019590613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546101c190613dc2565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561026657602002820191906000526020600020905b815481526020019060010190808311610252575b5050505050815250509050919050565b600080604051806060016040528086600981111561029657610296613aa7565b81526020018581526020018481525090506102b081610ac1565b9150505b9392505050565b6102c36139e4565b6102ce848484610310565b949350505050565b60008060405180606001604052808660098111156102f6576102f6613aa7565b81526020018581526020018481525090506102b081610acc565b6103186139e4565b81518351146103a05760408051634bab873760e11b81526004810191909152600d60448201526c72756e74696d6556616c75657360981b606482015260806024820152602260848201527f6d7573742062652073616d65206c656e6774682061732072756e74696d654b6560a482015261797360f01b60c482015260e4015b60405180910390fd5b60006103ab85610c26565b805490915060ff1660018160098111156103c7576103c7613aa7565b036104755761046c6103da838787610c84565b8360010180546103e990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461041590613dc2565b80156104625780601f1061043757610100808354040283529160200191610462565b820191906000526020600020905b81548152906001019060200180831161044557829003601f168201915b5050505050610d46565b925050506102b4565b600281600981111561048957610489613aa7565b036105305761046c61049c838787610c84565b8360010180546104ab90613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546104d790613dc2565b80156105245780601f106104f957610100808354040283529160200191610524565b820191906000526020600020905b81548152906001019060200180831161050757829003601f168201915b50505050508787610ebb565b600381600981111561054457610544613aa7565b036105de5761046c82600101805461055b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461058790613dc2565b80156105d45780601f106105a9576101008083540402835291602001916105d4565b820191906000526020600020905b8154815290600101906020018083116105b757829003601f168201915b5050505050610f59565b60048160098111156105f2576105f2613aa7565b0361068c5761046c82600101805461060990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461063590613dc2565b80156106825780601f1061065757610100808354040283529160200191610682565b820191906000526020600020905b81548152906001019060200180831161066557829003601f168201915b5050505050611087565b60058160098111156106a0576106a0613aa7565b0361073a5761046c8260010180546106b790613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546106e390613dc2565b80156107305780601f1061070557610100808354040283529160200191610730565b820191906000526020600020905b81548152906001019060200180831161071357829003601f168201915b505050505061131e565b600981600981111561074e5761074e613aa7565b036107ea5761046c82600101805461076590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461079190613dc2565b80156107de5780601f106107b3576101008083540402835291602001916107de565b820191906000526020600020905b8154815290600101906020018083116107c157829003601f168201915b505050505086866114b5565b60068160098111156107fe576107fe613aa7565b036108a35761046c610811838787610c84565b83600101805461082090613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461084c90613dc2565b80156108995780601f1061086e57610100808354040283529160200191610899565b820191906000526020600020905b81548152906001019060200180831161087c57829003601f168201915b50505050506115c7565b60078160098111156108b7576108b7613aa7565b036109ec576040805160608101909152825461046c91908490829060ff1660098111156108e6576108e6613aa7565b60098111156108f7576108f7613aa7565b815260200160018201805461090b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461093790613dc2565b80156109845780601f1061095957610100808354040283529160200191610984565b820191906000526020600020905b81548152906001019060200180831161096757829003601f168201915b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109dc57602002820191906000526020600020905b8154815260200190600101908083116109c8575b5050505050815250508686611728565b6008816009811115610a0057610a00613aa7565b03610a9a5761046c826001018054610a1790613dc2565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4390613dc2565b8015610a905780601f10610a6557610100808354040283529160200191610a90565b820191906000526020600020905b815481529060010190602001808311610a7357829003601f168201915b50505050506118a5565b6040516323a9bbc960e01b815260048101879052602401610397565b600061011682610c26565b6000610116826118ea565b6000610ad782610ac1565b9050610ae28161192a565b15610b35577fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e81836000015184602001518560400151604051610b289493929190613e32565b60405180910390a1919050565b610b3e82611a8c565b610b5d578160405163382bbbc960e11b81526004016103979190613b21565b60005b826040015151811015610bd957610b9383604001518281518110610b8657610b86613e6a565b602002602001015161192a565b610bd15782604001518181518110610bad57610bad613e6a565b6020026020010151604051632f19f96160e11b815260040161039791815260200190565b600101610b60565b50610be382611c31565b8351602085015160408087015190519395507fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e9450610b28938693929190613e32565b604080516020808201839052606082018190527f696f2e73796e7468657469782e6f7261636c652d6d616e616765722e4e6f6465608080840191909152828401949094528251808303909401845260a0909101909152815191012090565b600283015460609067ffffffffffffffff811115610ca457610ca4613b9a565b604051908082528060200260200182016040528015610cdd57816020015b610cca6139e4565b815260200190600190039081610cc25790505b50905060005b6002850154811015610d3e57610d19856002018281548110610d0757610d07613e6a565b90600052602060002001548585610310565b828281518110610d2b57610d2b613e6a565b6020908102919091010152600101610ce3565b509392505050565b610d4e6139e4565b600082806020019051810190610d649190613e80565b90506000816008811115610d7a57610d7a613aa7565b03610d9057610d8884611ca5565b915050610116565b6001816008811115610da457610da4613aa7565b03610db257610d8884611d0d565b6002816008811115610dc657610dc6613aa7565b03610dd457610d8884611d90565b6003816008811115610de857610de8613aa7565b03610df657610d8884611e13565b6004816008811115610e0a57610e0a613aa7565b03610e1857610d8884611ec9565b6005816008811115610e2c57610e2c613aa7565b03610e3a57610d8884612009565b6006816008811115610e4e57610e4e613aa7565b03610e5c57610d88846120e4565b6007816008811115610e7057610e70613aa7565b03610e7e57610d888461220c565b6008816008811115610e9257610e92613aa7565b03610ea057610d88846122ce565b80604051631be413d360e11b81526004016103979190613ea1565b610ec36139e4565b600084806020019051810190610ed99190613ed3565b604051631ecba7c360e31b81529091506001600160a01b0382169063f65d3e1890610f0e908990899089908990600401613ef0565b608060405180830381865afa158015610f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4f9190613f91565b9695505050505050565b610f616139e4565b600080600084806020019051810190610f7a9190613fe8565b92509250925060008390506000806000836001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fec9190614041565b509350509250925060008660001461100f5761100a8585858a6123c7565b611011565b825b905060128660ff161161103b5761103661102f60ff881660126140a7565b82906124c2565b611053565b61105361104c601260ff89166140a7565b82906124dc565b9050604051806080016040528082815260200183815260200160008152602001600081525098505050505050505050919050565b61108f6139e4565b600080600080600080878060200190518101906110ac91906140ba565b604080516002808252606082018352979d50959b50939950919750955093506000929060208301908036833701905050905081816000815181106110f2576110f2613e6a565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061112157611121613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526000906001600160a01b0385169063883bdbfd90611165908590600401614143565b600060405180830381865afa158015611182573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111aa91908101906141f5565b5090506000816000815181106111c2576111c2613e6a565b6020026020010151826001815181106111dd576111dd613e6a565b60200260200101516111ef91906142c1565b9050600061121761120563ffffffff87166124f6565b61120f9084614304565b60060b61252d565b905060008260060b12801561124c575061123b63ffffffff8616612569565b612569565b8260060b6112499190614342565b15155b1561125f578061125b81614356565b9150505b600061126d6012600a61445d565b9050600061128061123684848f8f612593565b905060006112908a60ff16612569565b61129c8c60ff16612569565b6112a6919061446c565b905060008082136112d1576112cc6112c56112c084614493565b612686565b84906124dc565b6112e4565b6112e46112dd83612686565b84906124c2565b905060405180608001604052808281526020014281526020016000815260200160008152509e505050505050505050505050505050919050565b6113266139e4565b60008060008480602001905181019061133f91906144bf565b91945092509050826000826113bc576040516396834ad360e01b8152600481018590526001600160a01b038316906396834ad390602401608060405180830381865afa158015611393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b791906144f5565b611425565b604051639474f45b60e01b8152600481018590526001600160a01b03831690639474f45b90602401608060405180830381865afa158015611401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142591906144f5565b90506000816040015160030b601261143d919061456f565b90506000808213611467576114626114576112c084614493565b845160070b906124dc565b61147e565b61147e61147383612686565b845160070b906124c2565b9050604051806080016040528082815260200184606001518152602001600081526020016000815250975050505050505050919050565b6114bd6139e4565b6000806000868060200190518101906114d69190614597565b92509250925060005b8651811015611545578681815181106114fa576114fa613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b0361153d5785818151811061152f5761152f613e6a565b602002602001015160001c91505b6001016114df565b5060408051600180825281830190925260009160208083019080368337019050509050828160008151811061157c5761157c613e6a565b602002602001018181525050836001838360405160200161159f939291906145ce565b60408051601f198184030181529082905263cf2cabdf60e01b82526103979291600401614603565b6115cf6139e4565b6000828060200190518101906115e59190614627565b90506000846000815181106115fc576115fc613e6a565b602002602001015160000151905060008560018151811061161f5761161f613e6a565b6020026020010151600001519050808214611702576000611653601261164d611648858761446c565b6126a9565b906124c2565b905082158061167b5750611666836126a9565b6116709082614640565b61167985612569565b125b15611700576002875111156116b0578660028151811061169d5761169d613e6a565b6020026020010151945050505050610116565b826000036116d15760405163014cc07160e01b815260040160405180910390fd5b6116da836126a9565b6116e49082614640565b60405163dcac091960e01b815260040161039791815260200190565b505b8560008151811061171557611715613e6a565b6020026020010151935050505092915050565b6117306139e4565b6000846020015180602001905181019061174a9190614627565b905060005b84518110156117bc5784818151811061176a5761176a613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b036117b4576117ad8482815181106117a2576117a2613e6a565b602002602001015190565b91506117bc565b60010161174f565b50600085604001516000815181106117d6576117d6613e6a565b6020026020010151905060006117ed828787610310565b60208101519091506117ff84426140a7565b1161180e5792506102b4915050565b86604001515160010361187157866040015160008151811061183257611832613e6a565b602002602001015181600001518260200151604051631808066560e21b8152600401610397939291909283526020830191909152604082015260600190565b61189a876040015160018151811061188b5761188b613e6a565b60200260200101518787610310565b979650505050505050565b6118ad6139e4565b6040518060800160405280838060200190518101906118cc9190614627565b81526020014281526020016000815260200160008152509050919050565b600081600001518260200151836040015160405160200161190d9392919061466e565b604051602081830303815290604052805190602001209050919050565b60008061193683610c26565b60408051606081019091528154909190829060ff16600981111561195c5761195c613aa7565b600981111561196d5761196d613aa7565b815260200160018201805461198190613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546119ad90613dc2565b80156119fa5780601f106119cf576101008083540402835291602001916119fa565b820191906000526020600020905b8154815290600101906020018083116119dd57829003601f168201915b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015611a5257602002820191906000526020600020905b815481526020019060010190808311611a3e575b505050505081525050905060006009811115611a7057611a70613aa7565b81516009811115611a8357611a83613aa7565b14159392505050565b6000600182516009811115611aa357611aa3613aa7565b1480611ac15750600682516009811115611abf57611abf613aa7565b145b80611ade5750600782516009811115611adc57611adc613aa7565b145b15611aee57611aec826126c1565b505b600182516009811115611b0357611b03613aa7565b03611b11576101168261284a565b600282516009811115611b2657611b26613aa7565b03611b3457610116826128a5565b600382516009811115611b4957611b49613aa7565b03611b575761011682612973565b600482516009811115611b6c57611b6c613aa7565b03611b7a5761011682612aae565b600582516009811115611b8f57611b8f613aa7565b03611b9d5761011682612e92565b600982516009811115611bb257611bb2613aa7565b03611bc05761011682612fcb565b600682516009811115611bd557611bd5613aa7565b03611be3576101168261300e565b600782516009811115611bf857611bf8613aa7565b03611c065761011682613052565b600882516009811115611c1b57611c1b613aa7565b03611c295761011682613078565b506000919050565b600080611c3d836118ea565b9050611c4881610c26565b8351815491935090839060ff19166001836009811115611c6a57611c6a613aa7565b021790555060208301516001830190611c8390826146ed565b5060408301518051611c9f916002850191602090910190613a0c565b50915091565b611cad6139e4565b60005b8251811015611d07578160200151838281518110611cd057611cd0613e6a565b6020026020010151602001511115611cff57828181518110611cf457611cf4613e6a565b602002602001015191505b600101611cb0565b50919050565b611d156139e4565b81600081518110611d2857611d28613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611d5957611d59613e6a565b6020026020010151600001511215611d8857828181518110611d7d57611d7d613e6a565b602002602001015191505b600101611d39565b611d986139e4565b81600081518110611dab57611dab613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611ddc57611ddc613e6a565b6020026020010151600001511315611e0b57828181518110611e0057611e00613e6a565b602002602001015191505b600101611dbc565b611e1b6139e4565b60005b8251811015611e9557828181518110611e3957611e39613e6a565b60200260200101516000015182600001818151611e56919061456f565b9052508251839082908110611e6d57611e6d613e6a565b60200260200101516020015182602001818151611e8a91906147ad565b905250600101611e1e565b50611ea08251612569565b8151611eac9190614640565b815281516020820151611ebf91906147c0565b6020820152919050565b611ed16139e4565b611eed826000611ee86001865161123691906140a7565b6130a4565b60028251611efb91906147d4565b600003611fd65760408051600280825260608201909252600091816020015b611f226139e4565b815260200190600190039081611f1a57905050905082600160028551611f4891906147c0565b611f5291906140a7565b81518110611f6257611f62613e6a565b602002602001015181600081518110611f7d57611f7d613e6a565b60200260200101819052508260028451611f9791906147c0565b81518110611fa757611fa7613e6a565b602002602001015181600181518110611fc257611fc2613e6a565b60200260200101819052506102b481611e13565b8160028351611fe591906147c0565b81518110611ff557611ff5613e6a565b60200260200101519050919050565b919050565b6120116139e4565b8160008151811061202457612024613e6a565b60209081029190910101515181528151829060009061204557612045613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061207657612076613e6a565b6020026020010151600001518260000181815161209391906147e8565b90525082518390829081106120aa576120aa613e6a565b602002602001015160200151826020018181516120c791906147ad565b90525060010161205b565b5081518160200151611ebf91906147c0565b6120ec6139e4565b816000815181106120ff576120ff613e6a565b60209081029190910101515181528151829060009061212057612120613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061215157612151613e6a565b60200260200101516000015160000361219e5782818151811061217657612176613e6a565b6020026020010151600001516040516338ee04a760e01b815260040161039791815260200190565b8281815181106121b0576121b0613e6a565b602002602001015160000151826000018181516121cd9190614640565b90525082518390829081106121e4576121e4613e6a565b6020026020010151602001518260200181815161220191906147ad565b905250600101612136565b6122146139e4565b8160008151811061222757612227613e6a565b60209081029190910101515181528151829060009061224857612248613e6a565b6020908102919091018101518101519082015260015b82518110156120d25761229083828151811061227c5761227c613e6a565b602090810291909101015151835190613264565b825282518390829081106122a6576122a6613e6a565b602002602001015160200151826020018181516122c391906147ad565b90525060010161225e565b6122d66139e4565b816000815181106122e9576122e9613e6a565b60209081029190910101515181528151829060009061230a5761230a613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061233b5761233b613e6a565b6020026020010151600001516000036123605782818151811061217657612176613e6a565b61238983828151811061237557612375613e6a565b602090810291909101015151835190613283565b8252825183908290811061239f5761239f613e6a565b602002602001015160200151826020018181516123bc91906147ad565b905250600101612320565b6000826001826123d785426140a7565b90505b69ffffffffffffffffffff8716156124a3576001600160a01b038816639a6fc8f561240489614818565b6040516001600160e01b031960e084901b16815269ffffffffffffffffffff8216600482015290995060240160a060405180830381865afa925050508015612469575060408051601f3d908101601f1916820190925261246691810190614041565b60015b156124a357858210156124805750505050506124a3565b61248a848961456f565b97508661249681614834565b97505050505050506123da565b6124ac82612569565b6124b69084614640565b98975050505050505050565b60006124d261123683600a61484d565b6102b490846147e8565b60006124ec61123683600a61484d565b6102b49084614640565b6000667fffffffffffff66ffffffffffffff83161115612529576040516329d2678160e21b815260040160405180910390fd5b5090565b6000627fffff19600683900b128061254b5750627fffff600683900b135b1561252957604051630d962f7960e21b815260040160405180910390fd5b60006001600160ff1b038211156125295760405163677c430560e11b815260040160405180910390fd5b60008061259f86613298565b90506fffffffffffffffffffffffffffffffff6001600160a01b0382161161261c5760006125d66001600160a01b03831680614859565b9050836001600160a01b0316856001600160a01b03161061260557612600600160c01b87836136cd565b612614565b6126148187600160c01b6136cd565b92505061267d565b600061263b6001600160a01b03831680680100000000000000006136cd565b9050836001600160a01b0316856001600160a01b03161061266a57612665600160801b87836136cd565b612679565b6126798187600160801b6136cd565b9250505b50949350505050565b6000808212156125295760405163029f024d60e31b815260040160405180910390fd5b600080821215612529576126bc82614493565b610116565b6000805b8260400151518110156128415760006126fa846040015183815181106126ed576126ed613e6a565b6020026020010151610ab6565b60408051606081019091528154909190829060ff16600981111561272057612720613aa7565b600981111561273157612731613aa7565b815260200160018201805461274590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461277190613dc2565b80156127be5780601f10612793576101008083540402835291602001916127be565b820191906000526020600020905b8154815290600101906020018083116127a157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561281657602002820191906000526020600020905b815481526020019060010190808311612802575b505050505081525050905061282a81611a8c565b612838575060009392505050565b506001016126c5565b50600192915050565b60006002826040015151101561286257506000919050565b81602001515160201461287757506000919050565b600082602001518060200190518101906128919190614627565b905060088111156128415750600092915050565b6000602082602001515110156128bd57506000919050565b600082602001518060200190518101906128d79190613ed3565b90506128ea816306e7ea3960e21b6138e2565b6128f75750600092915050565b604051633b70a5bf60e21b81526001600160a01b0382169063edc296fc90612923908690600401613b21565b6020604051808303816000875af1158015612942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129669190614870565b6128415750600092915050565b6040810151516000901561298957506000919050565b81602001515160601461299e57506000919050565b60008083602001518060200190518101906129b99190613fe8565b92505091506000829050806001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a259190614041565b5050505050806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061488b565b60ff168260ff1614612aa357506000949350505050565b506001949350505050565b60408101515160009015612ac457506000919050565b81602001515160c014612ad957506000919050565b6000806000806000808760200151806020019051810190612afa91906140ba565b9550955095509550955095508360ff16866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6c919061488b565b60ff1614612b8257506000979650505050505050565b8260ff16856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be8919061488b565b60ff1614612bfe57506000979650505050505050565b6000826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c629190613ed3565b90506000836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc89190613ed3565b9050876001600160a01b0316826001600160a01b0316148015612cfc5750866001600160a01b0316816001600160a01b0316145b158015612d385750866001600160a01b0316826001600160a01b0316148015612d365750876001600160a01b0316816001600160a01b0316145b155b15612d4d575060009998505050505050505050565b60128660ff161180612d62575060128560ff16115b15612d77575060009998505050505050505050565b8263ffffffff16600003612d95575060009998505050505050505050565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612dca57612dca613e6a565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110612df957612df9613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526001600160a01b0386169063883bdbfd90612e3a908490600401614143565b600060405180830381865afa158015612e57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7f91908101906141f5565b5060019c9b505050505050505050505050565b60408101515160009015612ea857506000919050565b816020015151606014612ebd57506000919050565b60008060008460200151806020019051810190612eda91906144bf565b919450925090508281612f55576040516396834ad360e01b8152600481018490526001600160a01b038216906396834ad390602401608060405180830381865afa158015612f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5091906144f5565b612fbe565b604051639474f45b60e01b8152600481018490526001600160a01b03821690639474f45b90602401608060405180830381865afa158015612f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbe91906144f5565b5060019695505050505050565b60408101515160009015612fe157506000919050565b816020015151606014612ff657506000919050565b8160200151806020019051810190612aa39190614597565b60008160400151516002148061302957508160400151516003145b61303557506000919050565b81602001515160201461304a57506000919050565b506001919050565b600081604001515160011480613029575081604001515160021461303557506000919050565b6040810151516000901561308e57506000919050565b6020826020015151101561304a57506000919050565b81818082036130b4575050505050565b6000856130da60026130c6888861446c565b6130d09190614640565b6112c0908861456f565b815181106130ea576130ea613e6a565b60200260200101516000015190505b818313613236575b808661310c85612686565b8151811061311c5761311c613e6a565b60200260200101516000015112156131405782613138816148a6565b935050613101565b8561314a83612686565b8151811061315a5761315a613e6a565b60200260200101516000015181121561317f5781613177816148be565b925050613140565b818313613231578561319083612686565b815181106131a0576131a0613e6a565b6020026020010151866131b285612686565b815181106131c2576131c2613e6a565b6020026020010151876131d486612686565b815181106131e4576131e4613e6a565b60200260200101886131f586612686565b8151811061320557613205613e6a565b602002602001018290528290525050828061321f906148a6565b935050818061322d906148be565b9250505b6130f9565b81851215613249576132498686846130a4565b8383121561325c5761325c8684866130a4565b505050505050565b6000670de0b6b3a764000061327983856147e8565b6102b49190614640565b600081613279670de0b6b3a7640000856147e8565b60008060008360020b126132b8576132b3600284900b612686565b6132c8565b6132c86112c0600285900b614493565b90506132e36112c06132dd620d89e7196148db565b60020b90565b8111156133165760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401610397565b60008160011660000361332d57600160801b61333f565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561337e576080613379826ffff97272373d413259a46990580e213a614859565b901c90505b60048216156133a85760806133a3826ffff2e50f5f656932ef12357cf3c7fdcc614859565b901c90505b60088216156133d25760806133cd826fffe5caca7e10e4e61c3624eaa0941cd0614859565b901c90505b60108216156133fc5760806133f7826fffcb9843d60f6159c9db58835c926644614859565b901c90505b6020821615613426576080613421826fff973b41fa98c081472e6896dfb254c0614859565b901c90505b604082161561345057608061344b826fff2ea16466c96a3843ec78b326b52861614859565b901c90505b608082161561347a576080613475826ffe5dee046a99a2a811c461f1969c3053614859565b901c90505b6101008216156134a55760806134a0826ffcbe86c7900a88aedcffc83b479aa3a4614859565b901c90505b6102008216156134d05760806134cb826ff987a7253ac413176f2b074cf7815e54614859565b901c90505b6104008216156134fb5760806134f6826ff3392b0822b70005940c7a398e4b70f3614859565b901c90505b610800821615613526576080613521826fe7159475a2c29b7443b29c7fa6e889d9614859565b901c90505b61100082161561355157608061354c826fd097f3bdfd2022b8845ad8f792aa5825614859565b901c90505b61200082161561357c576080613577826fa9f746462d870fdf8a65dc1f90e061e5614859565b901c90505b6140008216156135a75760806135a2826f70d869a156d2a1b890bb3df62baf32f7614859565b901c90505b6180008216156135d25760806135cd826f31be135f97d08fd981231505542fcfa6614859565b901c90505b620100008216156135fe5760806135f9826f09aa508b5b7a84e1c677de54f3e99bc9614859565b901c90505b62020000821615613629576080613624826e5d6af8dedb81196699c329225ee604614859565b901c90505b6204000082161561365357608061364e826d2216e584f5fa1ea926041bedfe98614859565b901c90505b6208000082161561367b576080613676826b048a170391f7dc42444e8fa2614859565b901c90505b60008460020b131561369657613693816000196147c0565b90505b6102ce6136a8640100000000836147d4565b156136b45760016136b7565b60005b6136c89060ff16602084901c6147ad565b6139ba565b6000808060001985870985870292508281108382030391505080600003613749576000841161373e5760405162461bcd60e51b815260206004820152601960248201527f48616e646c65206e6f6e2d6f766572666c6f77206361736573000000000000006044820152606401610397565b5082900490506102b4565b8084116137985760405162461bcd60e51b815260206004820152601960248201527f70726576656e74732064656e6f6d696e61746f72203d3d2030000000000000006044820152606401610397565b60008486880980840393811190920391905060006137d06137b887612569565b6137c188612569565b6137ca90614493565b16612686565b9586900495938490049360008190030460010190506137ef8184614859565b909317926000613800876003614859565b600218905061380f8188614859565b61381a9060026140a7565b6138249082614859565b90506138308188614859565b61383b9060026140a7565b6138459082614859565b90506138518188614859565b61385c9060026140a7565b6138669082614859565b90506138728188614859565b61387d9060026140a7565b6138879082614859565b90506138938188614859565b61389e9060026140a7565b6138a89082614859565b90506138b48188614859565b6138bf9060026140a7565b6138c99082614859565b90506138d58186614859565b9998505050505050505050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b1790529051600091829182916001600160a01b0387169161394391906148fd565b6000604051808303816000865af19150503d8060008114613980576040519150601f19603f3d011682016040523d82523d6000602084013e613985565b606091505b50915091508161399a57600092505050610116565b80516000036139ae57600092505050610116565b60200151949350505050565b60006001600160a01b038211156125295760405163dccde8ed60e01b815260040160405180910390fd5b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054828255906000526020600020908101928215613a47579160200282015b82811115613a47578251825591602001919060010190613a2c565b506125299291505b808211156125295760008155600101613a4f565b600060208284031215613a7557600080fd5b5035919050565b8151815260208083015190820152604080830151908201526060808301519082015260808101610116565b634e487b7160e01b600052602160045260246000fd5b600a8110613acd57613acd613aa7565b9052565b60005b83811015613aec578181015183820152602001613ad4565b50506000910152565b60008151808452613b0d816020860160208601613ad1565b601f01601f19169290920160200192915050565b60006020808352613b358184018551613abd565b8084015160606040850152613b4d6080850182613af5565b6040860151858203601f19016060870152805180835290840192506000918401905b80831015613b8f5783518252928401926001929092019190840190613b6f565b509695505050505050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613bd357613bd3613b9a565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613c0257613c02613b9a565b604052919050565b600067ffffffffffffffff821115613c2457613c24613b9a565b5060051b60200190565b600082601f830112613c3f57600080fd5b81356020613c54613c4f83613c0a565b613bd9565b8083825260208201915060208460051b870101935086841115613c7657600080fd5b602086015b84811015613b8f5780358352918301918301613c7b565b600080600060608486031215613ca757600080fd5b8335600a8110613cb657600080fd5b925060208481013567ffffffffffffffff80821115613cd457600080fd5b818701915087601f830112613ce857600080fd5b813581811115613cfa57613cfa613b9a565b613d0c601f8201601f19168501613bd9565b8181528985838601011115613d2057600080fd5b818585018683013760009181019094015291935060408601359180831115613d4757600080fd5b5050613d5586828701613c2e565b9150509250925092565b600080600060608486031215613d7457600080fd5b83359250602084013567ffffffffffffffff80821115613d9357600080fd5b613d9f87838801613c2e565b93506040860135915080821115613db557600080fd5b50613d5586828701613c2e565b600181811c90821680613dd657607f821691505b602082108103611d0757634e487b7160e01b600052602260045260246000fd5b60008151808452602080850194506020840160005b83811015613e2757815187529582019590820190600101613e0b565b509495945050505050565b848152613e426020820185613abd565b608060408201526000613e586080830185613af5565b828103606084015261189a8185613df6565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613e9257600080fd5b8151600981106102b457600080fd5b6020810160098310613eb557613eb5613aa7565b91905290565b6001600160a01b0381168114613ed057600080fd5b50565b600060208284031215613ee557600080fd5b81516102b481613ebb565b608080825285518282018190526000919060209060a0850190828a01855b82811015613f5257613f42848351805182526020810151602083015260408101516040830152606081015160608301525050565b9285019290840190600101613f0e565b5050508481036020860152613f678189613af5565b925050508281036040840152613f7d8186613df6565b9050828103606084015261189a8185613df6565b600060808284031215613fa357600080fd5b613fab613bb0565b825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b805160ff8116811461200457600080fd5b600080600060608486031215613ffd57600080fd5b835161400881613ebb565b6020850151909350915061401e60408501613fd7565b90509250925092565b805169ffffffffffffffffffff8116811461200457600080fd5b600080600080600060a0868803121561405957600080fd5b61406286614027565b945060208601519350604086015192506060860151915061408560808701614027565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011657610116614091565b60008060008060008060c087890312156140d357600080fd5b86516140de81613ebb565b60208801519096506140ef81613ebb565b94506140fd60408801613fd7565b935061410b60608801613fd7565b9250608087015161411b81613ebb565b60a088015190925063ffffffff8116811461413557600080fd5b809150509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561418157835163ffffffff168352928401929184019160010161415f565b50909695505050505050565b600082601f83011261419e57600080fd5b815160206141ae613c4f83613c0a565b8083825260208201915060208460051b8701019350868411156141d057600080fd5b602086015b84811015613b8f5780516141e881613ebb565b83529183019183016141d5565b6000806040838503121561420857600080fd5b825167ffffffffffffffff8082111561422057600080fd5b818501915085601f83011261423457600080fd5b81516020614244613c4f83613c0a565b82815260059290921b8401810191818101908984111561426357600080fd5b948201945b838610156142915785518060060b81146142825760008081fd5b82529482019490820190614268565b918801519196509093505050808211156142aa57600080fd5b506142b78582860161418d565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff8213171561011657610116614091565b634e487b7160e01b600052601260045260246000fd5b60008160060b8360060b8061431b5761431b6142ee565b667fffffffffffff1982146000198214161561433957614339614091565b90059392505050565b600082614351576143516142ee565b500790565b60008160020b627fffff19810361436f5761436f614091565b6000190192915050565b600181815b808511156143b457816000190482111561439a5761439a614091565b808516156143a757918102915b93841c939080029061437e565b509250929050565b6000826143cb57506001610116565b816143d857506000610116565b81600181146143ee57600281146143f857614414565b6001915050610116565b60ff84111561440957614409614091565b50506001821b610116565b5060208310610133831016604e8410600b8410161715614437575081810a610116565b6144418383614379565b806000190482111561445557614455614091565b029392505050565b60006102b460ff8416836143bc565b818103600083128015838313168383128216171561448c5761448c614091565b5092915050565b6000600160ff1b82016144a8576144a8614091565b5060000390565b8051801515811461200457600080fd5b6000806000606084860312156144d457600080fd5b83516144df81613ebb565b6020850151909350915061401e604085016144af565b60006080828403121561450757600080fd5b61450f613bb0565b82518060070b811461452057600080fd5b8152602083015167ffffffffffffffff8116811461453d57600080fd5b60208201526040830151600381900b811461455757600080fd5b60408201526060928301519281019290925250919050565b808201828112600083128015821682158216171561458f5761458f614091565b505092915050565b6000806000606084860312156145ac57600080fd5b83516145b781613ebb565b602085015160409095015190969495509392505050565b60ff8416815267ffffffffffffffff831660208201526060604082015260006145fa6060830184613df6565b95945050505050565b6001600160a01b03831681526040602082018190526000906102ce90830184613af5565b60006020828403121561463957600080fd5b5051919050565b60008261464f5761464f6142ee565b600160ff1b82146000198414161561466957614669614091565b500590565b6146788185613abd565b60606020820152600061468e6060830185613af5565b8281036040840152610f4f8185613df6565b601f8211156146e8576000816000526020600020601f850160051c810160208610156146c95750805b601f850160051c820191505b8181101561325c578281556001016146d5565b505050565b815167ffffffffffffffff81111561470757614707613b9a565b61471b816147158454613dc2565b846146a0565b602080601f83116001811461475057600084156147385750858301515b600019600386901b1c1916600185901b17855561325c565b600085815260208120601f198616915b8281101561477f57888601518255948401946001909101908401614760565b508582101561479d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082018082111561011657610116614091565b6000826147cf576147cf6142ee565b500490565b6000826147e3576147e36142ee565b500690565b80820260008212600160ff1b8414161561480457614804614091565b818105831482151761011657610116614091565b600069ffffffffffffffffffff82168061436f5761436f614091565b60006001820161484657614846614091565b5060010190565b60006102b483836143bc565b808202811582820484141761011657610116614091565b60006020828403121561488257600080fd5b6102b4826144af565b60006020828403121561489d57600080fd5b6102b482613fd7565b60006001600160ff1b01820161484657614846614091565b6000600160ff1b82016148d3576148d3614091565b506000190190565b60008160020b627fffff1981036148f4576148f4614091565b60000392915050565b6000825161490f818460208701613ad1565b919091019291505056fea264697066735822122074f32fef384fdc296b0859f1c1f941c8e736c6cb972aa9e2b894956ebd6a80b364736f6c63430008160033","storage":{}},"0x83a0444b93927c3afcbe46e522280390f748e171":{"nonce":1,"balance":"0x0","code":"0x6080604052366100135761001161001d565b005b61001b61001d565b005b6000610027610093565b90503660008037600080366000845af43d6000803e806000811461004a573d6000f35b3d6000fd5b600080823b905060008111915050919050565b6000806040516020016100749061017a565b6040516020818303038152906040528051906020012090508091505090565b600061009d6100c6565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000806040516020016100d89061020c565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006101646023836100f7565b915061016f82610108565b604082019050919050565b6000602082019050818103600083015261019381610157565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b60006101f66021836100f7565b91506102018261019a565b604082019050919050565b60006020820190508181036000830152610225816101e9565b905091905056fea2646970667358221220800da1f73cebd5e4afa07496d9bca6b6c4f526bdd3f4014ec15c70fe3a1c441364736f6c63430008110033","storage":{"0x5a648c35a2f5512218b4683cf10e03f5b7c9dc7346e1bf77d304ae97f60f592b":"0x108f53faf774d7c4c56f5bce9ca6e605ce8aeadd","0x5c7865864a2a990d80b5bb5c40e7b73a029960dc711fbb56120dfab976e92ea3":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266"}},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xc67e2bd3108604cf0168c0e5ef9cd6d78b9bb14b":{"nonce":1,"balance":"0x21e19c6edb7e2445f20","code":"0x","storage":{}},"0xeb045d78d273107348b0300c01d29b7552d622ab":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"nonce":1,"balance":"0x21e19e08b86820a43ea","code":"0x","storage":{}}},"best_block_number":"0x5","blocks":[{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0xcd346446ed010523161f40a5f2b512def549bfb79e165b4354488738416481f2","transactionsRoot":"0xb3a4689832e0b599260ae70362ffcf224b60571b35ff8836904a3d81e2675d66","receiptsRoot":"0x2d13fdc120ab90536fed583939de7fb68b64926a306c1f629593ca9c2c93b198","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x3ea90d","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x2e0b6260","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gasLimit":"0x3ea90d","maxFeePerGas":"0x83215600","maxPriorityFeePerGas":"0x3b9aca00","value":"0x0","accessList":[],"input":"0x608060405234801561001057600080fd5b5061494f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80632a952b2d1461005c57806350c946fe14610085578063625ca21c146100a5578063daa250be146100c6578063deba1b98146100d9575b600080fd5b61006f61006a366004613a63565b6100ec565b60405161007c9190613a7c565b60405180910390f35b610098610093366004613a63565b61011c565b60405161007c9190613b21565b6100b86100b3366004613c92565b610276565b60405190815260200161007c565b61006f6100d4366004613d5f565b6102bb565b6100b86100e7366004613c92565b6102d6565b6100f46139e4565b6040805160008082526020820190815281830190925261011691849190610310565b92915050565b6101416040805160608101909152806000815260200160608152602001606081525090565b61014a82610ab6565b60408051606081019091528154909190829060ff16600981111561017057610170613aa7565b600981111561018157610181613aa7565b815260200160018201805461019590613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546101c190613dc2565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561026657602002820191906000526020600020905b815481526020019060010190808311610252575b5050505050815250509050919050565b600080604051806060016040528086600981111561029657610296613aa7565b81526020018581526020018481525090506102b081610ac1565b9150505b9392505050565b6102c36139e4565b6102ce848484610310565b949350505050565b60008060405180606001604052808660098111156102f6576102f6613aa7565b81526020018581526020018481525090506102b081610acc565b6103186139e4565b81518351146103a05760408051634bab873760e11b81526004810191909152600d60448201526c72756e74696d6556616c75657360981b606482015260806024820152602260848201527f6d7573742062652073616d65206c656e6774682061732072756e74696d654b6560a482015261797360f01b60c482015260e4015b60405180910390fd5b60006103ab85610c26565b805490915060ff1660018160098111156103c7576103c7613aa7565b036104755761046c6103da838787610c84565b8360010180546103e990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461041590613dc2565b80156104625780601f1061043757610100808354040283529160200191610462565b820191906000526020600020905b81548152906001019060200180831161044557829003601f168201915b5050505050610d46565b925050506102b4565b600281600981111561048957610489613aa7565b036105305761046c61049c838787610c84565b8360010180546104ab90613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546104d790613dc2565b80156105245780601f106104f957610100808354040283529160200191610524565b820191906000526020600020905b81548152906001019060200180831161050757829003601f168201915b50505050508787610ebb565b600381600981111561054457610544613aa7565b036105de5761046c82600101805461055b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461058790613dc2565b80156105d45780601f106105a9576101008083540402835291602001916105d4565b820191906000526020600020905b8154815290600101906020018083116105b757829003601f168201915b5050505050610f59565b60048160098111156105f2576105f2613aa7565b0361068c5761046c82600101805461060990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461063590613dc2565b80156106825780601f1061065757610100808354040283529160200191610682565b820191906000526020600020905b81548152906001019060200180831161066557829003601f168201915b5050505050611087565b60058160098111156106a0576106a0613aa7565b0361073a5761046c8260010180546106b790613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546106e390613dc2565b80156107305780601f1061070557610100808354040283529160200191610730565b820191906000526020600020905b81548152906001019060200180831161071357829003601f168201915b505050505061131e565b600981600981111561074e5761074e613aa7565b036107ea5761046c82600101805461076590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461079190613dc2565b80156107de5780601f106107b3576101008083540402835291602001916107de565b820191906000526020600020905b8154815290600101906020018083116107c157829003601f168201915b505050505086866114b5565b60068160098111156107fe576107fe613aa7565b036108a35761046c610811838787610c84565b83600101805461082090613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461084c90613dc2565b80156108995780601f1061086e57610100808354040283529160200191610899565b820191906000526020600020905b81548152906001019060200180831161087c57829003601f168201915b50505050506115c7565b60078160098111156108b7576108b7613aa7565b036109ec576040805160608101909152825461046c91908490829060ff1660098111156108e6576108e6613aa7565b60098111156108f7576108f7613aa7565b815260200160018201805461090b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461093790613dc2565b80156109845780601f1061095957610100808354040283529160200191610984565b820191906000526020600020905b81548152906001019060200180831161096757829003601f168201915b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109dc57602002820191906000526020600020905b8154815260200190600101908083116109c8575b5050505050815250508686611728565b6008816009811115610a0057610a00613aa7565b03610a9a5761046c826001018054610a1790613dc2565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4390613dc2565b8015610a905780601f10610a6557610100808354040283529160200191610a90565b820191906000526020600020905b815481529060010190602001808311610a7357829003601f168201915b50505050506118a5565b6040516323a9bbc960e01b815260048101879052602401610397565b600061011682610c26565b6000610116826118ea565b6000610ad782610ac1565b9050610ae28161192a565b15610b35577fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e81836000015184602001518560400151604051610b289493929190613e32565b60405180910390a1919050565b610b3e82611a8c565b610b5d578160405163382bbbc960e11b81526004016103979190613b21565b60005b826040015151811015610bd957610b9383604001518281518110610b8657610b86613e6a565b602002602001015161192a565b610bd15782604001518181518110610bad57610bad613e6a565b6020026020010151604051632f19f96160e11b815260040161039791815260200190565b600101610b60565b50610be382611c31565b8351602085015160408087015190519395507fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e9450610b28938693929190613e32565b604080516020808201839052606082018190527f696f2e73796e7468657469782e6f7261636c652d6d616e616765722e4e6f6465608080840191909152828401949094528251808303909401845260a0909101909152815191012090565b600283015460609067ffffffffffffffff811115610ca457610ca4613b9a565b604051908082528060200260200182016040528015610cdd57816020015b610cca6139e4565b815260200190600190039081610cc25790505b50905060005b6002850154811015610d3e57610d19856002018281548110610d0757610d07613e6a565b90600052602060002001548585610310565b828281518110610d2b57610d2b613e6a565b6020908102919091010152600101610ce3565b509392505050565b610d4e6139e4565b600082806020019051810190610d649190613e80565b90506000816008811115610d7a57610d7a613aa7565b03610d9057610d8884611ca5565b915050610116565b6001816008811115610da457610da4613aa7565b03610db257610d8884611d0d565b6002816008811115610dc657610dc6613aa7565b03610dd457610d8884611d90565b6003816008811115610de857610de8613aa7565b03610df657610d8884611e13565b6004816008811115610e0a57610e0a613aa7565b03610e1857610d8884611ec9565b6005816008811115610e2c57610e2c613aa7565b03610e3a57610d8884612009565b6006816008811115610e4e57610e4e613aa7565b03610e5c57610d88846120e4565b6007816008811115610e7057610e70613aa7565b03610e7e57610d888461220c565b6008816008811115610e9257610e92613aa7565b03610ea057610d88846122ce565b80604051631be413d360e11b81526004016103979190613ea1565b610ec36139e4565b600084806020019051810190610ed99190613ed3565b604051631ecba7c360e31b81529091506001600160a01b0382169063f65d3e1890610f0e908990899089908990600401613ef0565b608060405180830381865afa158015610f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4f9190613f91565b9695505050505050565b610f616139e4565b600080600084806020019051810190610f7a9190613fe8565b92509250925060008390506000806000836001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fec9190614041565b509350509250925060008660001461100f5761100a8585858a6123c7565b611011565b825b905060128660ff161161103b5761103661102f60ff881660126140a7565b82906124c2565b611053565b61105361104c601260ff89166140a7565b82906124dc565b9050604051806080016040528082815260200183815260200160008152602001600081525098505050505050505050919050565b61108f6139e4565b600080600080600080878060200190518101906110ac91906140ba565b604080516002808252606082018352979d50959b50939950919750955093506000929060208301908036833701905050905081816000815181106110f2576110f2613e6a565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061112157611121613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526000906001600160a01b0385169063883bdbfd90611165908590600401614143565b600060405180830381865afa158015611182573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111aa91908101906141f5565b5090506000816000815181106111c2576111c2613e6a565b6020026020010151826001815181106111dd576111dd613e6a565b60200260200101516111ef91906142c1565b9050600061121761120563ffffffff87166124f6565b61120f9084614304565b60060b61252d565b905060008260060b12801561124c575061123b63ffffffff8616612569565b612569565b8260060b6112499190614342565b15155b1561125f578061125b81614356565b9150505b600061126d6012600a61445d565b9050600061128061123684848f8f612593565b905060006112908a60ff16612569565b61129c8c60ff16612569565b6112a6919061446c565b905060008082136112d1576112cc6112c56112c084614493565b612686565b84906124dc565b6112e4565b6112e46112dd83612686565b84906124c2565b905060405180608001604052808281526020014281526020016000815260200160008152509e505050505050505050505050505050919050565b6113266139e4565b60008060008480602001905181019061133f91906144bf565b91945092509050826000826113bc576040516396834ad360e01b8152600481018590526001600160a01b038316906396834ad390602401608060405180830381865afa158015611393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b791906144f5565b611425565b604051639474f45b60e01b8152600481018590526001600160a01b03831690639474f45b90602401608060405180830381865afa158015611401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142591906144f5565b90506000816040015160030b601261143d919061456f565b90506000808213611467576114626114576112c084614493565b845160070b906124dc565b61147e565b61147e61147383612686565b845160070b906124c2565b9050604051806080016040528082815260200184606001518152602001600081526020016000815250975050505050505050919050565b6114bd6139e4565b6000806000868060200190518101906114d69190614597565b92509250925060005b8651811015611545578681815181106114fa576114fa613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b0361153d5785818151811061152f5761152f613e6a565b602002602001015160001c91505b6001016114df565b5060408051600180825281830190925260009160208083019080368337019050509050828160008151811061157c5761157c613e6a565b602002602001018181525050836001838360405160200161159f939291906145ce565b60408051601f198184030181529082905263cf2cabdf60e01b82526103979291600401614603565b6115cf6139e4565b6000828060200190518101906115e59190614627565b90506000846000815181106115fc576115fc613e6a565b602002602001015160000151905060008560018151811061161f5761161f613e6a565b6020026020010151600001519050808214611702576000611653601261164d611648858761446c565b6126a9565b906124c2565b905082158061167b5750611666836126a9565b6116709082614640565b61167985612569565b125b15611700576002875111156116b0578660028151811061169d5761169d613e6a565b6020026020010151945050505050610116565b826000036116d15760405163014cc07160e01b815260040160405180910390fd5b6116da836126a9565b6116e49082614640565b60405163dcac091960e01b815260040161039791815260200190565b505b8560008151811061171557611715613e6a565b6020026020010151935050505092915050565b6117306139e4565b6000846020015180602001905181019061174a9190614627565b905060005b84518110156117bc5784818151811061176a5761176a613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b036117b4576117ad8482815181106117a2576117a2613e6a565b602002602001015190565b91506117bc565b60010161174f565b50600085604001516000815181106117d6576117d6613e6a565b6020026020010151905060006117ed828787610310565b60208101519091506117ff84426140a7565b1161180e5792506102b4915050565b86604001515160010361187157866040015160008151811061183257611832613e6a565b602002602001015181600001518260200151604051631808066560e21b8152600401610397939291909283526020830191909152604082015260600190565b61189a876040015160018151811061188b5761188b613e6a565b60200260200101518787610310565b979650505050505050565b6118ad6139e4565b6040518060800160405280838060200190518101906118cc9190614627565b81526020014281526020016000815260200160008152509050919050565b600081600001518260200151836040015160405160200161190d9392919061466e565b604051602081830303815290604052805190602001209050919050565b60008061193683610c26565b60408051606081019091528154909190829060ff16600981111561195c5761195c613aa7565b600981111561196d5761196d613aa7565b815260200160018201805461198190613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546119ad90613dc2565b80156119fa5780601f106119cf576101008083540402835291602001916119fa565b820191906000526020600020905b8154815290600101906020018083116119dd57829003601f168201915b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015611a5257602002820191906000526020600020905b815481526020019060010190808311611a3e575b505050505081525050905060006009811115611a7057611a70613aa7565b81516009811115611a8357611a83613aa7565b14159392505050565b6000600182516009811115611aa357611aa3613aa7565b1480611ac15750600682516009811115611abf57611abf613aa7565b145b80611ade5750600782516009811115611adc57611adc613aa7565b145b15611aee57611aec826126c1565b505b600182516009811115611b0357611b03613aa7565b03611b11576101168261284a565b600282516009811115611b2657611b26613aa7565b03611b3457610116826128a5565b600382516009811115611b4957611b49613aa7565b03611b575761011682612973565b600482516009811115611b6c57611b6c613aa7565b03611b7a5761011682612aae565b600582516009811115611b8f57611b8f613aa7565b03611b9d5761011682612e92565b600982516009811115611bb257611bb2613aa7565b03611bc05761011682612fcb565b600682516009811115611bd557611bd5613aa7565b03611be3576101168261300e565b600782516009811115611bf857611bf8613aa7565b03611c065761011682613052565b600882516009811115611c1b57611c1b613aa7565b03611c295761011682613078565b506000919050565b600080611c3d836118ea565b9050611c4881610c26565b8351815491935090839060ff19166001836009811115611c6a57611c6a613aa7565b021790555060208301516001830190611c8390826146ed565b5060408301518051611c9f916002850191602090910190613a0c565b50915091565b611cad6139e4565b60005b8251811015611d07578160200151838281518110611cd057611cd0613e6a565b6020026020010151602001511115611cff57828181518110611cf457611cf4613e6a565b602002602001015191505b600101611cb0565b50919050565b611d156139e4565b81600081518110611d2857611d28613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611d5957611d59613e6a565b6020026020010151600001511215611d8857828181518110611d7d57611d7d613e6a565b602002602001015191505b600101611d39565b611d986139e4565b81600081518110611dab57611dab613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611ddc57611ddc613e6a565b6020026020010151600001511315611e0b57828181518110611e0057611e00613e6a565b602002602001015191505b600101611dbc565b611e1b6139e4565b60005b8251811015611e9557828181518110611e3957611e39613e6a565b60200260200101516000015182600001818151611e56919061456f565b9052508251839082908110611e6d57611e6d613e6a565b60200260200101516020015182602001818151611e8a91906147ad565b905250600101611e1e565b50611ea08251612569565b8151611eac9190614640565b815281516020820151611ebf91906147c0565b6020820152919050565b611ed16139e4565b611eed826000611ee86001865161123691906140a7565b6130a4565b60028251611efb91906147d4565b600003611fd65760408051600280825260608201909252600091816020015b611f226139e4565b815260200190600190039081611f1a57905050905082600160028551611f4891906147c0565b611f5291906140a7565b81518110611f6257611f62613e6a565b602002602001015181600081518110611f7d57611f7d613e6a565b60200260200101819052508260028451611f9791906147c0565b81518110611fa757611fa7613e6a565b602002602001015181600181518110611fc257611fc2613e6a565b60200260200101819052506102b481611e13565b8160028351611fe591906147c0565b81518110611ff557611ff5613e6a565b60200260200101519050919050565b919050565b6120116139e4565b8160008151811061202457612024613e6a565b60209081029190910101515181528151829060009061204557612045613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061207657612076613e6a565b6020026020010151600001518260000181815161209391906147e8565b90525082518390829081106120aa576120aa613e6a565b602002602001015160200151826020018181516120c791906147ad565b90525060010161205b565b5081518160200151611ebf91906147c0565b6120ec6139e4565b816000815181106120ff576120ff613e6a565b60209081029190910101515181528151829060009061212057612120613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061215157612151613e6a565b60200260200101516000015160000361219e5782818151811061217657612176613e6a565b6020026020010151600001516040516338ee04a760e01b815260040161039791815260200190565b8281815181106121b0576121b0613e6a565b602002602001015160000151826000018181516121cd9190614640565b90525082518390829081106121e4576121e4613e6a565b6020026020010151602001518260200181815161220191906147ad565b905250600101612136565b6122146139e4565b8160008151811061222757612227613e6a565b60209081029190910101515181528151829060009061224857612248613e6a565b6020908102919091018101518101519082015260015b82518110156120d25761229083828151811061227c5761227c613e6a565b602090810291909101015151835190613264565b825282518390829081106122a6576122a6613e6a565b602002602001015160200151826020018181516122c391906147ad565b90525060010161225e565b6122d66139e4565b816000815181106122e9576122e9613e6a565b60209081029190910101515181528151829060009061230a5761230a613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061233b5761233b613e6a565b6020026020010151600001516000036123605782818151811061217657612176613e6a565b61238983828151811061237557612375613e6a565b602090810291909101015151835190613283565b8252825183908290811061239f5761239f613e6a565b602002602001015160200151826020018181516123bc91906147ad565b905250600101612320565b6000826001826123d785426140a7565b90505b69ffffffffffffffffffff8716156124a3576001600160a01b038816639a6fc8f561240489614818565b6040516001600160e01b031960e084901b16815269ffffffffffffffffffff8216600482015290995060240160a060405180830381865afa925050508015612469575060408051601f3d908101601f1916820190925261246691810190614041565b60015b156124a357858210156124805750505050506124a3565b61248a848961456f565b97508661249681614834565b97505050505050506123da565b6124ac82612569565b6124b69084614640565b98975050505050505050565b60006124d261123683600a61484d565b6102b490846147e8565b60006124ec61123683600a61484d565b6102b49084614640565b6000667fffffffffffff66ffffffffffffff83161115612529576040516329d2678160e21b815260040160405180910390fd5b5090565b6000627fffff19600683900b128061254b5750627fffff600683900b135b1561252957604051630d962f7960e21b815260040160405180910390fd5b60006001600160ff1b038211156125295760405163677c430560e11b815260040160405180910390fd5b60008061259f86613298565b90506fffffffffffffffffffffffffffffffff6001600160a01b0382161161261c5760006125d66001600160a01b03831680614859565b9050836001600160a01b0316856001600160a01b03161061260557612600600160c01b87836136cd565b612614565b6126148187600160c01b6136cd565b92505061267d565b600061263b6001600160a01b03831680680100000000000000006136cd565b9050836001600160a01b0316856001600160a01b03161061266a57612665600160801b87836136cd565b612679565b6126798187600160801b6136cd565b9250505b50949350505050565b6000808212156125295760405163029f024d60e31b815260040160405180910390fd5b600080821215612529576126bc82614493565b610116565b6000805b8260400151518110156128415760006126fa846040015183815181106126ed576126ed613e6a565b6020026020010151610ab6565b60408051606081019091528154909190829060ff16600981111561272057612720613aa7565b600981111561273157612731613aa7565b815260200160018201805461274590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461277190613dc2565b80156127be5780601f10612793576101008083540402835291602001916127be565b820191906000526020600020905b8154815290600101906020018083116127a157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561281657602002820191906000526020600020905b815481526020019060010190808311612802575b505050505081525050905061282a81611a8c565b612838575060009392505050565b506001016126c5565b50600192915050565b60006002826040015151101561286257506000919050565b81602001515160201461287757506000919050565b600082602001518060200190518101906128919190614627565b905060088111156128415750600092915050565b6000602082602001515110156128bd57506000919050565b600082602001518060200190518101906128d79190613ed3565b90506128ea816306e7ea3960e21b6138e2565b6128f75750600092915050565b604051633b70a5bf60e21b81526001600160a01b0382169063edc296fc90612923908690600401613b21565b6020604051808303816000875af1158015612942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129669190614870565b6128415750600092915050565b6040810151516000901561298957506000919050565b81602001515160601461299e57506000919050565b60008083602001518060200190518101906129b99190613fe8565b92505091506000829050806001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a259190614041565b5050505050806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061488b565b60ff168260ff1614612aa357506000949350505050565b506001949350505050565b60408101515160009015612ac457506000919050565b81602001515160c014612ad957506000919050565b6000806000806000808760200151806020019051810190612afa91906140ba565b9550955095509550955095508360ff16866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6c919061488b565b60ff1614612b8257506000979650505050505050565b8260ff16856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be8919061488b565b60ff1614612bfe57506000979650505050505050565b6000826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c629190613ed3565b90506000836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc89190613ed3565b9050876001600160a01b0316826001600160a01b0316148015612cfc5750866001600160a01b0316816001600160a01b0316145b158015612d385750866001600160a01b0316826001600160a01b0316148015612d365750876001600160a01b0316816001600160a01b0316145b155b15612d4d575060009998505050505050505050565b60128660ff161180612d62575060128560ff16115b15612d77575060009998505050505050505050565b8263ffffffff16600003612d95575060009998505050505050505050565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612dca57612dca613e6a565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110612df957612df9613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526001600160a01b0386169063883bdbfd90612e3a908490600401614143565b600060405180830381865afa158015612e57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7f91908101906141f5565b5060019c9b505050505050505050505050565b60408101515160009015612ea857506000919050565b816020015151606014612ebd57506000919050565b60008060008460200151806020019051810190612eda91906144bf565b919450925090508281612f55576040516396834ad360e01b8152600481018490526001600160a01b038216906396834ad390602401608060405180830381865afa158015612f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5091906144f5565b612fbe565b604051639474f45b60e01b8152600481018490526001600160a01b03821690639474f45b90602401608060405180830381865afa158015612f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbe91906144f5565b5060019695505050505050565b60408101515160009015612fe157506000919050565b816020015151606014612ff657506000919050565b8160200151806020019051810190612aa39190614597565b60008160400151516002148061302957508160400151516003145b61303557506000919050565b81602001515160201461304a57506000919050565b506001919050565b600081604001515160011480613029575081604001515160021461303557506000919050565b6040810151516000901561308e57506000919050565b6020826020015151101561304a57506000919050565b81818082036130b4575050505050565b6000856130da60026130c6888861446c565b6130d09190614640565b6112c0908861456f565b815181106130ea576130ea613e6a565b60200260200101516000015190505b818313613236575b808661310c85612686565b8151811061311c5761311c613e6a565b60200260200101516000015112156131405782613138816148a6565b935050613101565b8561314a83612686565b8151811061315a5761315a613e6a565b60200260200101516000015181121561317f5781613177816148be565b925050613140565b818313613231578561319083612686565b815181106131a0576131a0613e6a565b6020026020010151866131b285612686565b815181106131c2576131c2613e6a565b6020026020010151876131d486612686565b815181106131e4576131e4613e6a565b60200260200101886131f586612686565b8151811061320557613205613e6a565b602002602001018290528290525050828061321f906148a6565b935050818061322d906148be565b9250505b6130f9565b81851215613249576132498686846130a4565b8383121561325c5761325c8684866130a4565b505050505050565b6000670de0b6b3a764000061327983856147e8565b6102b49190614640565b600081613279670de0b6b3a7640000856147e8565b60008060008360020b126132b8576132b3600284900b612686565b6132c8565b6132c86112c0600285900b614493565b90506132e36112c06132dd620d89e7196148db565b60020b90565b8111156133165760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401610397565b60008160011660000361332d57600160801b61333f565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561337e576080613379826ffff97272373d413259a46990580e213a614859565b901c90505b60048216156133a85760806133a3826ffff2e50f5f656932ef12357cf3c7fdcc614859565b901c90505b60088216156133d25760806133cd826fffe5caca7e10e4e61c3624eaa0941cd0614859565b901c90505b60108216156133fc5760806133f7826fffcb9843d60f6159c9db58835c926644614859565b901c90505b6020821615613426576080613421826fff973b41fa98c081472e6896dfb254c0614859565b901c90505b604082161561345057608061344b826fff2ea16466c96a3843ec78b326b52861614859565b901c90505b608082161561347a576080613475826ffe5dee046a99a2a811c461f1969c3053614859565b901c90505b6101008216156134a55760806134a0826ffcbe86c7900a88aedcffc83b479aa3a4614859565b901c90505b6102008216156134d05760806134cb826ff987a7253ac413176f2b074cf7815e54614859565b901c90505b6104008216156134fb5760806134f6826ff3392b0822b70005940c7a398e4b70f3614859565b901c90505b610800821615613526576080613521826fe7159475a2c29b7443b29c7fa6e889d9614859565b901c90505b61100082161561355157608061354c826fd097f3bdfd2022b8845ad8f792aa5825614859565b901c90505b61200082161561357c576080613577826fa9f746462d870fdf8a65dc1f90e061e5614859565b901c90505b6140008216156135a75760806135a2826f70d869a156d2a1b890bb3df62baf32f7614859565b901c90505b6180008216156135d25760806135cd826f31be135f97d08fd981231505542fcfa6614859565b901c90505b620100008216156135fe5760806135f9826f09aa508b5b7a84e1c677de54f3e99bc9614859565b901c90505b62020000821615613629576080613624826e5d6af8dedb81196699c329225ee604614859565b901c90505b6204000082161561365357608061364e826d2216e584f5fa1ea926041bedfe98614859565b901c90505b6208000082161561367b576080613676826b048a170391f7dc42444e8fa2614859565b901c90505b60008460020b131561369657613693816000196147c0565b90505b6102ce6136a8640100000000836147d4565b156136b45760016136b7565b60005b6136c89060ff16602084901c6147ad565b6139ba565b6000808060001985870985870292508281108382030391505080600003613749576000841161373e5760405162461bcd60e51b815260206004820152601960248201527f48616e646c65206e6f6e2d6f766572666c6f77206361736573000000000000006044820152606401610397565b5082900490506102b4565b8084116137985760405162461bcd60e51b815260206004820152601960248201527f70726576656e74732064656e6f6d696e61746f72203d3d2030000000000000006044820152606401610397565b60008486880980840393811190920391905060006137d06137b887612569565b6137c188612569565b6137ca90614493565b16612686565b9586900495938490049360008190030460010190506137ef8184614859565b909317926000613800876003614859565b600218905061380f8188614859565b61381a9060026140a7565b6138249082614859565b90506138308188614859565b61383b9060026140a7565b6138459082614859565b90506138518188614859565b61385c9060026140a7565b6138669082614859565b90506138728188614859565b61387d9060026140a7565b6138879082614859565b90506138938188614859565b61389e9060026140a7565b6138a89082614859565b90506138b48188614859565b6138bf9060026140a7565b6138c99082614859565b90506138d58186614859565b9998505050505050505050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b1790529051600091829182916001600160a01b0387169161394391906148fd565b6000604051808303816000865af19150503d8060008114613980576040519150601f19603f3d011682016040523d82523d6000602084013e613985565b606091505b50915091508161399a57600092505050610116565b80516000036139ae57600092505050610116565b60200151949350505050565b60006001600160a01b038211156125295760405163dccde8ed60e01b815260040160405180910390fd5b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054828255906000526020600020908101928215613a47579160200282015b82811115613a47578251825591602001919060010190613a2c565b506125299291505b808211156125295760008155600101613a4f565b600060208284031215613a7557600080fd5b5035919050565b8151815260208083015190820152604080830151908201526060808301519082015260808101610116565b634e487b7160e01b600052602160045260246000fd5b600a8110613acd57613acd613aa7565b9052565b60005b83811015613aec578181015183820152602001613ad4565b50506000910152565b60008151808452613b0d816020860160208601613ad1565b601f01601f19169290920160200192915050565b60006020808352613b358184018551613abd565b8084015160606040850152613b4d6080850182613af5565b6040860151858203601f19016060870152805180835290840192506000918401905b80831015613b8f5783518252928401926001929092019190840190613b6f565b509695505050505050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613bd357613bd3613b9a565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613c0257613c02613b9a565b604052919050565b600067ffffffffffffffff821115613c2457613c24613b9a565b5060051b60200190565b600082601f830112613c3f57600080fd5b81356020613c54613c4f83613c0a565b613bd9565b8083825260208201915060208460051b870101935086841115613c7657600080fd5b602086015b84811015613b8f5780358352918301918301613c7b565b600080600060608486031215613ca757600080fd5b8335600a8110613cb657600080fd5b925060208481013567ffffffffffffffff80821115613cd457600080fd5b818701915087601f830112613ce857600080fd5b813581811115613cfa57613cfa613b9a565b613d0c601f8201601f19168501613bd9565b8181528985838601011115613d2057600080fd5b818585018683013760009181019094015291935060408601359180831115613d4757600080fd5b5050613d5586828701613c2e565b9150509250925092565b600080600060608486031215613d7457600080fd5b83359250602084013567ffffffffffffffff80821115613d9357600080fd5b613d9f87838801613c2e565b93506040860135915080821115613db557600080fd5b50613d5586828701613c2e565b600181811c90821680613dd657607f821691505b602082108103611d0757634e487b7160e01b600052602260045260246000fd5b60008151808452602080850194506020840160005b83811015613e2757815187529582019590820190600101613e0b565b509495945050505050565b848152613e426020820185613abd565b608060408201526000613e586080830185613af5565b828103606084015261189a8185613df6565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613e9257600080fd5b8151600981106102b457600080fd5b6020810160098310613eb557613eb5613aa7565b91905290565b6001600160a01b0381168114613ed057600080fd5b50565b600060208284031215613ee557600080fd5b81516102b481613ebb565b608080825285518282018190526000919060209060a0850190828a01855b82811015613f5257613f42848351805182526020810151602083015260408101516040830152606081015160608301525050565b9285019290840190600101613f0e565b5050508481036020860152613f678189613af5565b925050508281036040840152613f7d8186613df6565b9050828103606084015261189a8185613df6565b600060808284031215613fa357600080fd5b613fab613bb0565b825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b805160ff8116811461200457600080fd5b600080600060608486031215613ffd57600080fd5b835161400881613ebb565b6020850151909350915061401e60408501613fd7565b90509250925092565b805169ffffffffffffffffffff8116811461200457600080fd5b600080600080600060a0868803121561405957600080fd5b61406286614027565b945060208601519350604086015192506060860151915061408560808701614027565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011657610116614091565b60008060008060008060c087890312156140d357600080fd5b86516140de81613ebb565b60208801519096506140ef81613ebb565b94506140fd60408801613fd7565b935061410b60608801613fd7565b9250608087015161411b81613ebb565b60a088015190925063ffffffff8116811461413557600080fd5b809150509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561418157835163ffffffff168352928401929184019160010161415f565b50909695505050505050565b600082601f83011261419e57600080fd5b815160206141ae613c4f83613c0a565b8083825260208201915060208460051b8701019350868411156141d057600080fd5b602086015b84811015613b8f5780516141e881613ebb565b83529183019183016141d5565b6000806040838503121561420857600080fd5b825167ffffffffffffffff8082111561422057600080fd5b818501915085601f83011261423457600080fd5b81516020614244613c4f83613c0a565b82815260059290921b8401810191818101908984111561426357600080fd5b948201945b838610156142915785518060060b81146142825760008081fd5b82529482019490820190614268565b918801519196509093505050808211156142aa57600080fd5b506142b78582860161418d565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff8213171561011657610116614091565b634e487b7160e01b600052601260045260246000fd5b60008160060b8360060b8061431b5761431b6142ee565b667fffffffffffff1982146000198214161561433957614339614091565b90059392505050565b600082614351576143516142ee565b500790565b60008160020b627fffff19810361436f5761436f614091565b6000190192915050565b600181815b808511156143b457816000190482111561439a5761439a614091565b808516156143a757918102915b93841c939080029061437e565b509250929050565b6000826143cb57506001610116565b816143d857506000610116565b81600181146143ee57600281146143f857614414565b6001915050610116565b60ff84111561440957614409614091565b50506001821b610116565b5060208310610133831016604e8410600b8410161715614437575081810a610116565b6144418383614379565b806000190482111561445557614455614091565b029392505050565b60006102b460ff8416836143bc565b818103600083128015838313168383128216171561448c5761448c614091565b5092915050565b6000600160ff1b82016144a8576144a8614091565b5060000390565b8051801515811461200457600080fd5b6000806000606084860312156144d457600080fd5b83516144df81613ebb565b6020850151909350915061401e604085016144af565b60006080828403121561450757600080fd5b61450f613bb0565b82518060070b811461452057600080fd5b8152602083015167ffffffffffffffff8116811461453d57600080fd5b60208201526040830151600381900b811461455757600080fd5b60408201526060928301519281019290925250919050565b808201828112600083128015821682158216171561458f5761458f614091565b505092915050565b6000806000606084860312156145ac57600080fd5b83516145b781613ebb565b602085015160409095015190969495509392505050565b60ff8416815267ffffffffffffffff831660208201526060604082015260006145fa6060830184613df6565b95945050505050565b6001600160a01b03831681526040602082018190526000906102ce90830184613af5565b60006020828403121561463957600080fd5b5051919050565b60008261464f5761464f6142ee565b600160ff1b82146000198414161561466957614669614091565b500590565b6146788185613abd565b60606020820152600061468e6060830185613af5565b8281036040840152610f4f8185613df6565b601f8211156146e8576000816000526020600020601f850160051c810160208610156146c95750805b601f850160051c820191505b8181101561325c578281556001016146d5565b505050565b815167ffffffffffffffff81111561470757614707613b9a565b61471b816147158454613dc2565b846146a0565b602080601f83116001811461475057600084156147385750858301515b600019600386901b1c1916600185901b17855561325c565b600085815260208120601f198616915b8281101561477f57888601518255948401946001909101908401614760565b508582101561479d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082018082111561011657610116614091565b6000826147cf576147cf6142ee565b500490565b6000826147e3576147e36142ee565b500690565b80820260008212600160ff1b8414161561480457614804614091565b818105831482151761011657610116614091565b600069ffffffffffffffffffff82168061436f5761436f614091565b60006001820161484657614846614091565b5060010190565b60006102b483836143bc565b808202811582820484141761011657610116614091565b60006020828403121561488257600080fd5b6102b4826144af565b60006020828403121561489d57600080fd5b6102b482613fd7565b60006001600160ff1b01820161484657614846614091565b6000600160ff1b82016148d3576148d3614091565b506000190190565b60008160020b627fffff1981036148f4576148f4614091565b60000392915050565b6000825161490f818460208701613ad1565b919091019291505056fea264697066735822122074f32fef384fdc296b0859f1c1f941c8e736c6cb972aa9e2b894956ebd6a80b364736f6c63430008160033","r":"0x1","s":"0x1","yParity":"0x0","hash":"0xbc73db80bf4b8784ba10a8910a0b7ef85f6846d102b41dd990969ea205335354"}}],"ommers":[]},{"header":{"parentHash":"0x026ae0c6ae91f186a9befa1ac8be30eea35e30e77de51a731085221e5cd39209","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0xb6003e7ba07a15a9e35f63daa484728ec4ceeded0c4d10ac1b04e9552d412b3c","transactionsRoot":"0x6e4969a136061ca7a390d12830d47a151585325a8d396819fb2b958ff85e9f8f","receiptsRoot":"0xc3e81df67d3e2a6c8345a954ef250cfcc41abcc2292a5aa263071124533fc9ad","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x3","gasLimit":"0x1c9c380","gasUsed":"0x3c0f6","timestamp":"0x66b200ce","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x18993a68","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gasLimit":"0x3c0f6","maxFeePerGas":"0x5d4285cd","maxPriorityFeePerGas":"0x3b9aca00","value":"0x0","accessList":[],"input":"0x608060405234801561001057600080fd5b50610380806100206000396000f3fe6080604052600080357fffffffff0000000000000000000000000000000000000000000000000000000016905060008160e01c610251565b60006379ba509782101561015e5781631627540c811461009857632a952b2d81146100b457633659cfe681146100d0576350c946fe81146100ec576353a47bb781146101085763625ca21c81146101245763718fe928811461014057610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc91505b5061024c565b816379ba509781146101a657638da5cb5b81146101c25763aaf10f4281146101de5763c7f62cda81146101fa5763daa250be81146102165763deba1b9881146102325761024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b738138ef7cf908021d117e542120b7a39065016107915061024a565b738138ef7cf908021d117e542120b7a3906501610791505b505b919050565b61025a81610037565b915050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102ce57816040517fc2a825f50000000000000000000000000000000000000000000000000000000081526004016102c5919061032f565b60405180910390fd5b3660008037600080366000845af43d6000803e80600081146102ef573d6000f35b3d6000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610329816102f4565b82525050565b60006020820190506103446000830184610320565b9291505056fea264697066735822122017a4b7fdaaab3897a7b47abaed8d2ee92d558883d3bb2a8454f9601b2ab2c3db64736f6c63430008150033","r":"0x1","s":"0x1","yParity":"0x0","hash":"0x2476e039803622aeb040f924f04c493f559aed3d6c9372ab405cb33c8c695328"}}],"ommers":[]},{"header":{"parentHash":"0x3d22100ac0ee8d5cde334f7f926191a861b0648971ebc179547df28a0224c6d0","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x9511d4711e5c30a72b0bff38a261daa75dcc5ba8b772d970a5c742244b4c861b","transactionsRoot":"0xba5fff578d3d6c2cd63acbe9bca353eaa6fe22a5c408956eff49106e0a96c507","receiptsRoot":"0xbae111f01cb07677e3a8c5031546138407c01bc964d3493d732dc4edf47d36d3","logsBloom":"0x00000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000020000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000001000000000000000000000400000001000010000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x5","gasLimit":"0x1c9c380","gasUsed":"0xcae7","timestamp":"0x66b200cb","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x12e09c7a","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gasLimit":"0xcc4d","maxFeePerGas":"0x557e5ec4","maxPriorityFeePerGas":"0x3b9aca00","to":"0x83a0444b93927c3afcbe46e522280390f748e171","value":"0x0","accessList":[],"input":"0x3659cfe6000000000000000000000000108f53faf774d7c4c56f5bce9ca6e605ce8aeadd","r":"0x1","s":"0x1","yParity":"0x0","hash":"0xf88e7b19ee347145c257e0cf7ac4ecc2bae83ca79d7edaa231e71d3213aeb151"}}],"ommers":[]},{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x9c8eaf493f8b4edce2ba1647343eadcc0989cf461e712c0a6253ff2ca1842bb7","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0xdd07c07470e1deff3749831f0f1ad8d4b6e35505e83b3c6ea14181716197cd8a","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x29aa352e71b139e83b397bdd3dcf9b65d74770edaf3a9624d0dbc4f96f868680","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200cb","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x24a1ab52","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200c9","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0xf6930be4847cac5017bbcbec2756eed19f36b4196526a98a88e311c296e3a9be","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x29aa352e71b139e83b397bdd3dcf9b65d74770edaf3a9624d0dbc4f96f868680","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200cc","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x200d75e8","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0xb6003e7ba07a15a9e35f63daa484728ec4ceeded0c4d10ac1b04e9552d412b3c","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x4","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x1592fbf9","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x149d41e3b89d8324cef3feff98ef308e97bafe8745cc8461c60172bc7d4c44ba","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x510f2275449c013534a25ad0b13c867caf720947b68bcbcd4863f7b172a5d023","transactionsRoot":"0x0b44110186e52ff0ceb6b0776ca2992c94144a4ed712eef65ea038260ef0fcc7","receiptsRoot":"0xc2823b8eb4730d9f2657137cc2ddc2c4f22ab68e0ab826236cf6a1551ca2b3a5","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0xe61f9","timestamp":"0x66b200cb","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x342770c0","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gasLimit":"0xe94d1","maxFeePerGas":"0x83215600","maxPriorityFeePerGas":"0x3b9aca00","to":"0x4e59b44847b379578588920ca78fbf26c0b4956c","value":"0x0","accessList":[],"input":"0x4786e4342646b3ba97c1790b6cf5a55087a36240b22570f5d3a5d6bcc929d93b608060405234801561001057600080fd5b5060008061002661006d60201b61081b1760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610141565b60008060405160200161007f90610121565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b600061010b60238361009e565b9150610116826100af565b604082019050919050565b6000602082019050818103600083015261013a816100fe565b9050919050565b611000806101506000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c806379ba50971161005b57806379ba5097146100ed5780638da5cb5b146100f7578063aaf10f4214610115578063c7f62cda1461013357610088565b80631627540c1461008d5780633659cfe6146100a957806353a47bb7146100c5578063718fe928146100e3575b600080fd5b6100a760048036038101906100a29190610d25565b61014f565b005b6100c360048036038101906100be9190610d25565b6102d0565b005b6100cd6102e4565b6040516100da9190610d61565b60405180910390f35b6100eb610317565b005b6100f56103fe565b005b6100ff61058b565b60405161010c9190610d61565b60405180910390f35b61011d6105be565b60405161012a9190610d61565b60405180910390f35b61014d60048036038101906101489190610d25565b6105f1565b005b61015761084c565b600061016161081b565b9050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101c9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610252576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22826040516102c49190610d61565b60405180910390a15050565b6102d861084c565b6102e1816108c5565b50565b60006102ee61081b565b60010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600061032161081b565b90503373ffffffffffffffffffffffffffffffffffffffff168160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103b757336040517fa0e5a0d70000000000000000000000000000000000000000000000000000000081526004016103ae9190610d61565b60405180910390fd5b60008160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600061040861081b565b905060008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104a357336040517fa0e5a0d700000000000000000000000000000000000000000000000000000000815260040161049a9190610d61565b60405180910390fd5b7fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c8260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16826040516104f8929190610d7c565b60405180910390a1808260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b600061059561081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105c8610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105fb610b05565b905060018160000160146101000a81548160ff02191690831515021790555060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050828260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008373ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16633659cfe6846040516024016106cc9190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161071b9190610e16565b600060405180830381855af49150503d8060008114610756576040519150601f19603f3d011682016040523d82523d6000602084013e61075b565b606091505b505090508015806107c357508173ffffffffffffffffffffffffffffffffffffffff16610786610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b156107fa576040517fa1cfa5a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360000160146101000a81548160ff0219169083151502179055600080fd5b60008060405160200161082d90610eb0565b6040516020818303038152906040528051906020012090508091505090565b610854610b36565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108c357336040517f8e4a23d60000000000000000000000000000000000000000000000000000000081526004016108ba9190610d61565b60405180910390fd5b565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61093481610b69565b61097557806040517f8a8b41ec00000000000000000000000000000000000000000000000000000000815260040161096c9190610d61565b60405180910390fd5b600061097f610b05565b90508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610a0a576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000160149054906101000a900460ff16158015610a2e5750610a2d82610b7c565b5b15610a7057816040517f15504301000000000000000000000000000000000000000000000000000000008152600401610a679190610d61565b60405180910390fd5b818160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503073ffffffffffffffffffffffffffffffffffffffff167f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c783604051610af99190610d61565b60405180910390a25050565b600080604051602001610b1790610f42565b6040516020818303038152906040528051906020012090508091505090565b6000610b4061081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080823b905060008111915050919050565b60008060003073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1663c7f62cda86604051602401610bc59190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c149190610e16565b600060405180830381855af49150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509150915081158015610cb9575063a1cfa5a860e01b604051602001610c7a9190610faf565b6040516020818303038152906040528051906020012081604051602001610ca19190610e16565b60405160208183030381529060405280519060200120145b92505050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cf282610cc7565b9050919050565b610d0281610ce7565b8114610d0d57600080fd5b50565b600081359050610d1f81610cf9565b92915050565b600060208284031215610d3b57610d3a610cc2565b5b6000610d4984828501610d10565b91505092915050565b610d5b81610ce7565b82525050565b6000602082019050610d766000830184610d52565b92915050565b6000604082019050610d916000830185610d52565b610d9e6020830184610d52565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015610dd9578082015181840152602081019050610dbe565b60008484015250505050565b6000610df082610da5565b610dfa8185610db0565b9350610e0a818560208601610dbb565b80840191505092915050565b6000610e228284610de5565b915081905092915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b6000610e9a602383610e2d565b9150610ea582610e3e565b604082019050919050565b60006020820190508181036000830152610ec981610e8d565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b6000610f2c602183610e2d565b9150610f3782610ed0565b604082019050919050565b60006020820190508181036000830152610f5b81610f1f565b9050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610fa9610fa482610f62565b610f8e565b82525050565b6000610fbb8284610f98565b6004820191508190509291505056fea264697066735822122023a7c33d7b91dce35ffbcf8837693364ab22a3905d0fc00016833e5fac45ca2f64736f6c63430008110033","r":"0x1","s":"0x1","yParity":"0x0","hash":"0x4feae6769d748b4f0f7c9bf21d782236c88f13906789a3ec602961296e4c3e43"}}],"ommers":[]},{"header":{"parentHash":"0xb3535af5103fd1c2bbd6dc7ff23f0799037a6542c231ebcb85abd776560fa512","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x23d74fb99ff6e42cbb5c33f92b078e37be6af2b6092459b103ff7059a6517ebc","transactionsRoot":"0x9eab45eca206fe11c107ea985c7d02fcfa442836aea3e04ba11dc4df587d5aa6","receiptsRoot":"0xe25abcfa973db8c55f73292137c626430de130a382ad4466337fefb0f7c8fde0","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x3ce3f","timestamp":"0x66b200cd","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x1c0bc72b","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gasLimit":"0x3d8a8","maxFeePerGas":"0x6211577c","maxPriorityFeePerGas":"0x3b9aca00","to":"0x4e59b44847b379578588920ca78fbf26c0b4956c","value":"0x0","accessList":[],"input":"0x4786e4342646b3ba97c1790b6cf5a55087a36240b22570f5d3a5d6bcc929d93b608060405234801561001057600080fd5b5060405161068538038061068583398181016040528101906100329190610275565b818181600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361009b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6100ae8161019d60201b61004f1760201c565b6100ef57806040517f8a8b41ec0000000000000000000000000000000000000000000000000000000081526004016100e691906102c4565b60405180910390fd5b806100fe6101b060201b60201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050806101536101e160201b6100621760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050610414565b600080823b905060008111915050919050565b6000806040516020016101c290610362565b6040516020818303038152906040528051906020012090508091505090565b6000806040516020016101f3906103f4565b6040516020818303038152906040528051906020012090508091505090565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061024282610217565b9050919050565b61025281610237565b811461025d57600080fd5b50565b60008151905061026f81610249565b92915050565b6000806040838503121561028c5761028b610212565b5b600061029a85828601610260565b92505060206102ab85828601610260565b9150509250929050565b6102be81610237565b82525050565b60006020820190506102d960008301846102b5565b92915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b600061034c6021836102df565b9150610357826102f0565b604082019050919050565b6000602082019050818103600083015261037b8161033f565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006103de6023836102df565b91506103e982610382565b604082019050919050565b6000602082019050818103600083015261040d816103d1565b9050919050565b610262806104236000396000f3fe6080604052366100135761001161001d565b005b61001b61001d565b005b6000610027610093565b90503660008037600080366000845af43d6000803e806000811461004a573d6000f35b3d6000fd5b600080823b905060008111915050919050565b6000806040516020016100749061017a565b6040516020818303038152906040528051906020012090508091505090565b600061009d6100c6565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000806040516020016100d89061020c565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006101646023836100f7565b915061016f82610108565b604082019050919050565b6000602082019050818103600083015261019381610157565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b60006101f66021836100f7565b91506102018261019a565b604082019050919050565b60006020820190508181036000830152610225816101e9565b905091905056fea2646970667358221220800da1f73cebd5e4afa07496d9bca6b6c4f526bdd3f4014ec15c70fe3a1c441364736f6c6343000811003300000000000000000000000047d08dad17ccb558b3ea74b1a0e73a9cc804a9dc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266","r":"0x1","s":"0x1","yParity":"0x0","hash":"0xb6794d5c7abed6f91d447e8efb72ef2580595a6d7c8dee57ba1dbb330970146a"}}],"ommers":[]},{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x510f2275449c013534a25ad0b13c867caf720947b68bcbcd4863f7b172a5d023","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x3","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x29dd5614","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]}]} \ No newline at end of file +{"block":{"number":"0x5","coinbase":"0x0000000000000000000000000000000000000000","timestamp":"0x66b200cb","gas_limit":"0x1c9c380","basefee":"0x12e09c7a","difficulty":"0x0","prevrandao":"0xe7ef87fc7c2090741a6749a087e4ca8092cb4d07136008799e4ebeac3b69e34a","blob_excess_gas_and_price":{"excess_blob_gas":0,"blob_gasprice":1}},"accounts":{"0x0000000000000000000000000000000000000000":{"nonce":0,"balance":"0x1088aa62285a00","code":"0x","storage":{}},"0x108f53faf774d7c4c56f5bce9ca6e605ce8aeadd":{"nonce":1,"balance":"0x0","code":"0x6080604052600080357fffffffff0000000000000000000000000000000000000000000000000000000016905060008160e01c610251565b60006379ba509782101561015e5781631627540c811461009857632a952b2d81146100b457633659cfe681146100d0576350c946fe81146100ec576353a47bb781146101085763625ca21c81146101245763718fe928811461014057610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc91505b5061024c565b816379ba509781146101a657638da5cb5b81146101c25763aaf10f4281146101de5763c7f62cda81146101fa5763daa250be81146102165763deba1b9881146102325761024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b738138ef7cf908021d117e542120b7a39065016107915061024a565b738138ef7cf908021d117e542120b7a3906501610791505b505b919050565b61025a81610037565b915050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102ce57816040517fc2a825f50000000000000000000000000000000000000000000000000000000081526004016102c5919061032f565b60405180910390fd5b3660008037600080366000845af43d6000803e80600081146102ef573d6000f35b3d6000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610329816102f4565b82525050565b60006020820190506103446000830184610320565b9291505056fea264697066735822122017a4b7fdaaab3897a7b47abaed8d2ee92d558883d3bb2a8454f9601b2ab2c3db64736f6c63430008150033","storage":{}},"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x19ba1fac55eea44d12a01372a8eb0c2ebbf9ca21":{"nonce":1,"balance":"0x21e19df7c2963f0ac6b","code":"0x","storage":{}},"0x19c6ab860dbe2bc433574193a4409770a8748bf6":{"nonce":1,"balance":"0x21e19df8da6b7bdc410","code":"0x","storage":{}},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x40567ec443c1d1872af5155755ac3803cc3fe61e":{"nonce":1,"balance":"0x21e19da82562f921b40","code":"0x","storage":{}},"0x47d08dad17ccb558b3ea74b1a0e73a9cc804a9dc":{"nonce":1,"balance":"0x0","code":"0x608060405234801561001057600080fd5b50600436106100885760003560e01c806379ba50971161005b57806379ba5097146100ed5780638da5cb5b146100f7578063aaf10f4214610115578063c7f62cda1461013357610088565b80631627540c1461008d5780633659cfe6146100a957806353a47bb7146100c5578063718fe928146100e3575b600080fd5b6100a760048036038101906100a29190610d25565b61014f565b005b6100c360048036038101906100be9190610d25565b6102d0565b005b6100cd6102e4565b6040516100da9190610d61565b60405180910390f35b6100eb610317565b005b6100f56103fe565b005b6100ff61058b565b60405161010c9190610d61565b60405180910390f35b61011d6105be565b60405161012a9190610d61565b60405180910390f35b61014d60048036038101906101489190610d25565b6105f1565b005b61015761084c565b600061016161081b565b9050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101c9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610252576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22826040516102c49190610d61565b60405180910390a15050565b6102d861084c565b6102e1816108c5565b50565b60006102ee61081b565b60010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600061032161081b565b90503373ffffffffffffffffffffffffffffffffffffffff168160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103b757336040517fa0e5a0d70000000000000000000000000000000000000000000000000000000081526004016103ae9190610d61565b60405180910390fd5b60008160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600061040861081b565b905060008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104a357336040517fa0e5a0d700000000000000000000000000000000000000000000000000000000815260040161049a9190610d61565b60405180910390fd5b7fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c8260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16826040516104f8929190610d7c565b60405180910390a1808260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b600061059561081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105c8610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105fb610b05565b905060018160000160146101000a81548160ff02191690831515021790555060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050828260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008373ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16633659cfe6846040516024016106cc9190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161071b9190610e16565b600060405180830381855af49150503d8060008114610756576040519150601f19603f3d011682016040523d82523d6000602084013e61075b565b606091505b505090508015806107c357508173ffffffffffffffffffffffffffffffffffffffff16610786610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b156107fa576040517fa1cfa5a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360000160146101000a81548160ff0219169083151502179055600080fd5b60008060405160200161082d90610eb0565b6040516020818303038152906040528051906020012090508091505090565b610854610b36565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108c357336040517f8e4a23d60000000000000000000000000000000000000000000000000000000081526004016108ba9190610d61565b60405180910390fd5b565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61093481610b69565b61097557806040517f8a8b41ec00000000000000000000000000000000000000000000000000000000815260040161096c9190610d61565b60405180910390fd5b600061097f610b05565b90508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610a0a576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000160149054906101000a900460ff16158015610a2e5750610a2d82610b7c565b5b15610a7057816040517f15504301000000000000000000000000000000000000000000000000000000008152600401610a679190610d61565b60405180910390fd5b818160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503073ffffffffffffffffffffffffffffffffffffffff167f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c783604051610af99190610d61565b60405180910390a25050565b600080604051602001610b1790610f42565b6040516020818303038152906040528051906020012090508091505090565b6000610b4061081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080823b905060008111915050919050565b60008060003073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1663c7f62cda86604051602401610bc59190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c149190610e16565b600060405180830381855af49150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509150915081158015610cb9575063a1cfa5a860e01b604051602001610c7a9190610faf565b6040516020818303038152906040528051906020012081604051602001610ca19190610e16565b60405160208183030381529060405280519060200120145b92505050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cf282610cc7565b9050919050565b610d0281610ce7565b8114610d0d57600080fd5b50565b600081359050610d1f81610cf9565b92915050565b600060208284031215610d3b57610d3a610cc2565b5b6000610d4984828501610d10565b91505092915050565b610d5b81610ce7565b82525050565b6000602082019050610d766000830184610d52565b92915050565b6000604082019050610d916000830185610d52565b610d9e6020830184610d52565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015610dd9578082015181840152602081019050610dbe565b60008484015250505050565b6000610df082610da5565b610dfa8185610db0565b9350610e0a818560208601610dbb565b80840191505092915050565b6000610e228284610de5565b915081905092915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b6000610e9a602383610e2d565b9150610ea582610e3e565b604082019050919050565b60006020820190508181036000830152610ec981610e8d565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b6000610f2c602183610e2d565b9150610f3782610ed0565b604082019050919050565b60006020820190508181036000830152610f5b81610f1f565b9050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610fa9610fa482610f62565b610f8e565b82525050565b6000610fbb8284610f98565b6004820191508190509291505056fea264697066735822122023a7c33d7b91dce35ffbcf8837693364ab22a3905d0fc00016833e5fac45ca2f64736f6c63430008110033","storage":{"0x5c7865864a2a990d80b5bb5c40e7b73a029960dc711fbb56120dfab976e92ea3":"0x0"}},"0x4e59b44847b379578588920ca78fbf26c0b4956c":{"nonce":2,"balance":"0x0","code":"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3","storage":{}},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x8138ef7cf908021d117e542120b7a39065016107":{"nonce":1,"balance":"0x0","code":"0x608060405234801561001057600080fd5b50600436106100575760003560e01c80632a952b2d1461005c57806350c946fe14610085578063625ca21c146100a5578063daa250be146100c6578063deba1b98146100d9575b600080fd5b61006f61006a366004613a63565b6100ec565b60405161007c9190613a7c565b60405180910390f35b610098610093366004613a63565b61011c565b60405161007c9190613b21565b6100b86100b3366004613c92565b610276565b60405190815260200161007c565b61006f6100d4366004613d5f565b6102bb565b6100b86100e7366004613c92565b6102d6565b6100f46139e4565b6040805160008082526020820190815281830190925261011691849190610310565b92915050565b6101416040805160608101909152806000815260200160608152602001606081525090565b61014a82610ab6565b60408051606081019091528154909190829060ff16600981111561017057610170613aa7565b600981111561018157610181613aa7565b815260200160018201805461019590613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546101c190613dc2565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561026657602002820191906000526020600020905b815481526020019060010190808311610252575b5050505050815250509050919050565b600080604051806060016040528086600981111561029657610296613aa7565b81526020018581526020018481525090506102b081610ac1565b9150505b9392505050565b6102c36139e4565b6102ce848484610310565b949350505050565b60008060405180606001604052808660098111156102f6576102f6613aa7565b81526020018581526020018481525090506102b081610acc565b6103186139e4565b81518351146103a05760408051634bab873760e11b81526004810191909152600d60448201526c72756e74696d6556616c75657360981b606482015260806024820152602260848201527f6d7573742062652073616d65206c656e6774682061732072756e74696d654b6560a482015261797360f01b60c482015260e4015b60405180910390fd5b60006103ab85610c26565b805490915060ff1660018160098111156103c7576103c7613aa7565b036104755761046c6103da838787610c84565b8360010180546103e990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461041590613dc2565b80156104625780601f1061043757610100808354040283529160200191610462565b820191906000526020600020905b81548152906001019060200180831161044557829003601f168201915b5050505050610d46565b925050506102b4565b600281600981111561048957610489613aa7565b036105305761046c61049c838787610c84565b8360010180546104ab90613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546104d790613dc2565b80156105245780601f106104f957610100808354040283529160200191610524565b820191906000526020600020905b81548152906001019060200180831161050757829003601f168201915b50505050508787610ebb565b600381600981111561054457610544613aa7565b036105de5761046c82600101805461055b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461058790613dc2565b80156105d45780601f106105a9576101008083540402835291602001916105d4565b820191906000526020600020905b8154815290600101906020018083116105b757829003601f168201915b5050505050610f59565b60048160098111156105f2576105f2613aa7565b0361068c5761046c82600101805461060990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461063590613dc2565b80156106825780601f1061065757610100808354040283529160200191610682565b820191906000526020600020905b81548152906001019060200180831161066557829003601f168201915b5050505050611087565b60058160098111156106a0576106a0613aa7565b0361073a5761046c8260010180546106b790613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546106e390613dc2565b80156107305780601f1061070557610100808354040283529160200191610730565b820191906000526020600020905b81548152906001019060200180831161071357829003601f168201915b505050505061131e565b600981600981111561074e5761074e613aa7565b036107ea5761046c82600101805461076590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461079190613dc2565b80156107de5780601f106107b3576101008083540402835291602001916107de565b820191906000526020600020905b8154815290600101906020018083116107c157829003601f168201915b505050505086866114b5565b60068160098111156107fe576107fe613aa7565b036108a35761046c610811838787610c84565b83600101805461082090613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461084c90613dc2565b80156108995780601f1061086e57610100808354040283529160200191610899565b820191906000526020600020905b81548152906001019060200180831161087c57829003601f168201915b50505050506115c7565b60078160098111156108b7576108b7613aa7565b036109ec576040805160608101909152825461046c91908490829060ff1660098111156108e6576108e6613aa7565b60098111156108f7576108f7613aa7565b815260200160018201805461090b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461093790613dc2565b80156109845780601f1061095957610100808354040283529160200191610984565b820191906000526020600020905b81548152906001019060200180831161096757829003601f168201915b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109dc57602002820191906000526020600020905b8154815260200190600101908083116109c8575b5050505050815250508686611728565b6008816009811115610a0057610a00613aa7565b03610a9a5761046c826001018054610a1790613dc2565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4390613dc2565b8015610a905780601f10610a6557610100808354040283529160200191610a90565b820191906000526020600020905b815481529060010190602001808311610a7357829003601f168201915b50505050506118a5565b6040516323a9bbc960e01b815260048101879052602401610397565b600061011682610c26565b6000610116826118ea565b6000610ad782610ac1565b9050610ae28161192a565b15610b35577fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e81836000015184602001518560400151604051610b289493929190613e32565b60405180910390a1919050565b610b3e82611a8c565b610b5d578160405163382bbbc960e11b81526004016103979190613b21565b60005b826040015151811015610bd957610b9383604001518281518110610b8657610b86613e6a565b602002602001015161192a565b610bd15782604001518181518110610bad57610bad613e6a565b6020026020010151604051632f19f96160e11b815260040161039791815260200190565b600101610b60565b50610be382611c31565b8351602085015160408087015190519395507fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e9450610b28938693929190613e32565b604080516020808201839052606082018190527f696f2e73796e7468657469782e6f7261636c652d6d616e616765722e4e6f6465608080840191909152828401949094528251808303909401845260a0909101909152815191012090565b600283015460609067ffffffffffffffff811115610ca457610ca4613b9a565b604051908082528060200260200182016040528015610cdd57816020015b610cca6139e4565b815260200190600190039081610cc25790505b50905060005b6002850154811015610d3e57610d19856002018281548110610d0757610d07613e6a565b90600052602060002001548585610310565b828281518110610d2b57610d2b613e6a565b6020908102919091010152600101610ce3565b509392505050565b610d4e6139e4565b600082806020019051810190610d649190613e80565b90506000816008811115610d7a57610d7a613aa7565b03610d9057610d8884611ca5565b915050610116565b6001816008811115610da457610da4613aa7565b03610db257610d8884611d0d565b6002816008811115610dc657610dc6613aa7565b03610dd457610d8884611d90565b6003816008811115610de857610de8613aa7565b03610df657610d8884611e13565b6004816008811115610e0a57610e0a613aa7565b03610e1857610d8884611ec9565b6005816008811115610e2c57610e2c613aa7565b03610e3a57610d8884612009565b6006816008811115610e4e57610e4e613aa7565b03610e5c57610d88846120e4565b6007816008811115610e7057610e70613aa7565b03610e7e57610d888461220c565b6008816008811115610e9257610e92613aa7565b03610ea057610d88846122ce565b80604051631be413d360e11b81526004016103979190613ea1565b610ec36139e4565b600084806020019051810190610ed99190613ed3565b604051631ecba7c360e31b81529091506001600160a01b0382169063f65d3e1890610f0e908990899089908990600401613ef0565b608060405180830381865afa158015610f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4f9190613f91565b9695505050505050565b610f616139e4565b600080600084806020019051810190610f7a9190613fe8565b92509250925060008390506000806000836001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fec9190614041565b509350509250925060008660001461100f5761100a8585858a6123c7565b611011565b825b905060128660ff161161103b5761103661102f60ff881660126140a7565b82906124c2565b611053565b61105361104c601260ff89166140a7565b82906124dc565b9050604051806080016040528082815260200183815260200160008152602001600081525098505050505050505050919050565b61108f6139e4565b600080600080600080878060200190518101906110ac91906140ba565b604080516002808252606082018352979d50959b50939950919750955093506000929060208301908036833701905050905081816000815181106110f2576110f2613e6a565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061112157611121613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526000906001600160a01b0385169063883bdbfd90611165908590600401614143565b600060405180830381865afa158015611182573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111aa91908101906141f5565b5090506000816000815181106111c2576111c2613e6a565b6020026020010151826001815181106111dd576111dd613e6a565b60200260200101516111ef91906142c1565b9050600061121761120563ffffffff87166124f6565b61120f9084614304565b60060b61252d565b905060008260060b12801561124c575061123b63ffffffff8616612569565b612569565b8260060b6112499190614342565b15155b1561125f578061125b81614356565b9150505b600061126d6012600a61445d565b9050600061128061123684848f8f612593565b905060006112908a60ff16612569565b61129c8c60ff16612569565b6112a6919061446c565b905060008082136112d1576112cc6112c56112c084614493565b612686565b84906124dc565b6112e4565b6112e46112dd83612686565b84906124c2565b905060405180608001604052808281526020014281526020016000815260200160008152509e505050505050505050505050505050919050565b6113266139e4565b60008060008480602001905181019061133f91906144bf565b91945092509050826000826113bc576040516396834ad360e01b8152600481018590526001600160a01b038316906396834ad390602401608060405180830381865afa158015611393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b791906144f5565b611425565b604051639474f45b60e01b8152600481018590526001600160a01b03831690639474f45b90602401608060405180830381865afa158015611401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142591906144f5565b90506000816040015160030b601261143d919061456f565b90506000808213611467576114626114576112c084614493565b845160070b906124dc565b61147e565b61147e61147383612686565b845160070b906124c2565b9050604051806080016040528082815260200184606001518152602001600081526020016000815250975050505050505050919050565b6114bd6139e4565b6000806000868060200190518101906114d69190614597565b92509250925060005b8651811015611545578681815181106114fa576114fa613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b0361153d5785818151811061152f5761152f613e6a565b602002602001015160001c91505b6001016114df565b5060408051600180825281830190925260009160208083019080368337019050509050828160008151811061157c5761157c613e6a565b602002602001018181525050836001838360405160200161159f939291906145ce565b60408051601f198184030181529082905263cf2cabdf60e01b82526103979291600401614603565b6115cf6139e4565b6000828060200190518101906115e59190614627565b90506000846000815181106115fc576115fc613e6a565b602002602001015160000151905060008560018151811061161f5761161f613e6a565b6020026020010151600001519050808214611702576000611653601261164d611648858761446c565b6126a9565b906124c2565b905082158061167b5750611666836126a9565b6116709082614640565b61167985612569565b125b15611700576002875111156116b0578660028151811061169d5761169d613e6a565b6020026020010151945050505050610116565b826000036116d15760405163014cc07160e01b815260040160405180910390fd5b6116da836126a9565b6116e49082614640565b60405163dcac091960e01b815260040161039791815260200190565b505b8560008151811061171557611715613e6a565b6020026020010151935050505092915050565b6117306139e4565b6000846020015180602001905181019061174a9190614627565b905060005b84518110156117bc5784818151811061176a5761176a613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b036117b4576117ad8482815181106117a2576117a2613e6a565b602002602001015190565b91506117bc565b60010161174f565b50600085604001516000815181106117d6576117d6613e6a565b6020026020010151905060006117ed828787610310565b60208101519091506117ff84426140a7565b1161180e5792506102b4915050565b86604001515160010361187157866040015160008151811061183257611832613e6a565b602002602001015181600001518260200151604051631808066560e21b8152600401610397939291909283526020830191909152604082015260600190565b61189a876040015160018151811061188b5761188b613e6a565b60200260200101518787610310565b979650505050505050565b6118ad6139e4565b6040518060800160405280838060200190518101906118cc9190614627565b81526020014281526020016000815260200160008152509050919050565b600081600001518260200151836040015160405160200161190d9392919061466e565b604051602081830303815290604052805190602001209050919050565b60008061193683610c26565b60408051606081019091528154909190829060ff16600981111561195c5761195c613aa7565b600981111561196d5761196d613aa7565b815260200160018201805461198190613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546119ad90613dc2565b80156119fa5780601f106119cf576101008083540402835291602001916119fa565b820191906000526020600020905b8154815290600101906020018083116119dd57829003601f168201915b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015611a5257602002820191906000526020600020905b815481526020019060010190808311611a3e575b505050505081525050905060006009811115611a7057611a70613aa7565b81516009811115611a8357611a83613aa7565b14159392505050565b6000600182516009811115611aa357611aa3613aa7565b1480611ac15750600682516009811115611abf57611abf613aa7565b145b80611ade5750600782516009811115611adc57611adc613aa7565b145b15611aee57611aec826126c1565b505b600182516009811115611b0357611b03613aa7565b03611b11576101168261284a565b600282516009811115611b2657611b26613aa7565b03611b3457610116826128a5565b600382516009811115611b4957611b49613aa7565b03611b575761011682612973565b600482516009811115611b6c57611b6c613aa7565b03611b7a5761011682612aae565b600582516009811115611b8f57611b8f613aa7565b03611b9d5761011682612e92565b600982516009811115611bb257611bb2613aa7565b03611bc05761011682612fcb565b600682516009811115611bd557611bd5613aa7565b03611be3576101168261300e565b600782516009811115611bf857611bf8613aa7565b03611c065761011682613052565b600882516009811115611c1b57611c1b613aa7565b03611c295761011682613078565b506000919050565b600080611c3d836118ea565b9050611c4881610c26565b8351815491935090839060ff19166001836009811115611c6a57611c6a613aa7565b021790555060208301516001830190611c8390826146ed565b5060408301518051611c9f916002850191602090910190613a0c565b50915091565b611cad6139e4565b60005b8251811015611d07578160200151838281518110611cd057611cd0613e6a565b6020026020010151602001511115611cff57828181518110611cf457611cf4613e6a565b602002602001015191505b600101611cb0565b50919050565b611d156139e4565b81600081518110611d2857611d28613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611d5957611d59613e6a565b6020026020010151600001511215611d8857828181518110611d7d57611d7d613e6a565b602002602001015191505b600101611d39565b611d986139e4565b81600081518110611dab57611dab613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611ddc57611ddc613e6a565b6020026020010151600001511315611e0b57828181518110611e0057611e00613e6a565b602002602001015191505b600101611dbc565b611e1b6139e4565b60005b8251811015611e9557828181518110611e3957611e39613e6a565b60200260200101516000015182600001818151611e56919061456f565b9052508251839082908110611e6d57611e6d613e6a565b60200260200101516020015182602001818151611e8a91906147ad565b905250600101611e1e565b50611ea08251612569565b8151611eac9190614640565b815281516020820151611ebf91906147c0565b6020820152919050565b611ed16139e4565b611eed826000611ee86001865161123691906140a7565b6130a4565b60028251611efb91906147d4565b600003611fd65760408051600280825260608201909252600091816020015b611f226139e4565b815260200190600190039081611f1a57905050905082600160028551611f4891906147c0565b611f5291906140a7565b81518110611f6257611f62613e6a565b602002602001015181600081518110611f7d57611f7d613e6a565b60200260200101819052508260028451611f9791906147c0565b81518110611fa757611fa7613e6a565b602002602001015181600181518110611fc257611fc2613e6a565b60200260200101819052506102b481611e13565b8160028351611fe591906147c0565b81518110611ff557611ff5613e6a565b60200260200101519050919050565b919050565b6120116139e4565b8160008151811061202457612024613e6a565b60209081029190910101515181528151829060009061204557612045613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061207657612076613e6a565b6020026020010151600001518260000181815161209391906147e8565b90525082518390829081106120aa576120aa613e6a565b602002602001015160200151826020018181516120c791906147ad565b90525060010161205b565b5081518160200151611ebf91906147c0565b6120ec6139e4565b816000815181106120ff576120ff613e6a565b60209081029190910101515181528151829060009061212057612120613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061215157612151613e6a565b60200260200101516000015160000361219e5782818151811061217657612176613e6a565b6020026020010151600001516040516338ee04a760e01b815260040161039791815260200190565b8281815181106121b0576121b0613e6a565b602002602001015160000151826000018181516121cd9190614640565b90525082518390829081106121e4576121e4613e6a565b6020026020010151602001518260200181815161220191906147ad565b905250600101612136565b6122146139e4565b8160008151811061222757612227613e6a565b60209081029190910101515181528151829060009061224857612248613e6a565b6020908102919091018101518101519082015260015b82518110156120d25761229083828151811061227c5761227c613e6a565b602090810291909101015151835190613264565b825282518390829081106122a6576122a6613e6a565b602002602001015160200151826020018181516122c391906147ad565b90525060010161225e565b6122d66139e4565b816000815181106122e9576122e9613e6a565b60209081029190910101515181528151829060009061230a5761230a613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061233b5761233b613e6a565b6020026020010151600001516000036123605782818151811061217657612176613e6a565b61238983828151811061237557612375613e6a565b602090810291909101015151835190613283565b8252825183908290811061239f5761239f613e6a565b602002602001015160200151826020018181516123bc91906147ad565b905250600101612320565b6000826001826123d785426140a7565b90505b69ffffffffffffffffffff8716156124a3576001600160a01b038816639a6fc8f561240489614818565b6040516001600160e01b031960e084901b16815269ffffffffffffffffffff8216600482015290995060240160a060405180830381865afa925050508015612469575060408051601f3d908101601f1916820190925261246691810190614041565b60015b156124a357858210156124805750505050506124a3565b61248a848961456f565b97508661249681614834565b97505050505050506123da565b6124ac82612569565b6124b69084614640565b98975050505050505050565b60006124d261123683600a61484d565b6102b490846147e8565b60006124ec61123683600a61484d565b6102b49084614640565b6000667fffffffffffff66ffffffffffffff83161115612529576040516329d2678160e21b815260040160405180910390fd5b5090565b6000627fffff19600683900b128061254b5750627fffff600683900b135b1561252957604051630d962f7960e21b815260040160405180910390fd5b60006001600160ff1b038211156125295760405163677c430560e11b815260040160405180910390fd5b60008061259f86613298565b90506fffffffffffffffffffffffffffffffff6001600160a01b0382161161261c5760006125d66001600160a01b03831680614859565b9050836001600160a01b0316856001600160a01b03161061260557612600600160c01b87836136cd565b612614565b6126148187600160c01b6136cd565b92505061267d565b600061263b6001600160a01b03831680680100000000000000006136cd565b9050836001600160a01b0316856001600160a01b03161061266a57612665600160801b87836136cd565b612679565b6126798187600160801b6136cd565b9250505b50949350505050565b6000808212156125295760405163029f024d60e31b815260040160405180910390fd5b600080821215612529576126bc82614493565b610116565b6000805b8260400151518110156128415760006126fa846040015183815181106126ed576126ed613e6a565b6020026020010151610ab6565b60408051606081019091528154909190829060ff16600981111561272057612720613aa7565b600981111561273157612731613aa7565b815260200160018201805461274590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461277190613dc2565b80156127be5780601f10612793576101008083540402835291602001916127be565b820191906000526020600020905b8154815290600101906020018083116127a157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561281657602002820191906000526020600020905b815481526020019060010190808311612802575b505050505081525050905061282a81611a8c565b612838575060009392505050565b506001016126c5565b50600192915050565b60006002826040015151101561286257506000919050565b81602001515160201461287757506000919050565b600082602001518060200190518101906128919190614627565b905060088111156128415750600092915050565b6000602082602001515110156128bd57506000919050565b600082602001518060200190518101906128d79190613ed3565b90506128ea816306e7ea3960e21b6138e2565b6128f75750600092915050565b604051633b70a5bf60e21b81526001600160a01b0382169063edc296fc90612923908690600401613b21565b6020604051808303816000875af1158015612942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129669190614870565b6128415750600092915050565b6040810151516000901561298957506000919050565b81602001515160601461299e57506000919050565b60008083602001518060200190518101906129b99190613fe8565b92505091506000829050806001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a259190614041565b5050505050806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061488b565b60ff168260ff1614612aa357506000949350505050565b506001949350505050565b60408101515160009015612ac457506000919050565b81602001515160c014612ad957506000919050565b6000806000806000808760200151806020019051810190612afa91906140ba565b9550955095509550955095508360ff16866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6c919061488b565b60ff1614612b8257506000979650505050505050565b8260ff16856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be8919061488b565b60ff1614612bfe57506000979650505050505050565b6000826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c629190613ed3565b90506000836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc89190613ed3565b9050876001600160a01b0316826001600160a01b0316148015612cfc5750866001600160a01b0316816001600160a01b0316145b158015612d385750866001600160a01b0316826001600160a01b0316148015612d365750876001600160a01b0316816001600160a01b0316145b155b15612d4d575060009998505050505050505050565b60128660ff161180612d62575060128560ff16115b15612d77575060009998505050505050505050565b8263ffffffff16600003612d95575060009998505050505050505050565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612dca57612dca613e6a565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110612df957612df9613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526001600160a01b0386169063883bdbfd90612e3a908490600401614143565b600060405180830381865afa158015612e57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7f91908101906141f5565b5060019c9b505050505050505050505050565b60408101515160009015612ea857506000919050565b816020015151606014612ebd57506000919050565b60008060008460200151806020019051810190612eda91906144bf565b919450925090508281612f55576040516396834ad360e01b8152600481018490526001600160a01b038216906396834ad390602401608060405180830381865afa158015612f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5091906144f5565b612fbe565b604051639474f45b60e01b8152600481018490526001600160a01b03821690639474f45b90602401608060405180830381865afa158015612f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbe91906144f5565b5060019695505050505050565b60408101515160009015612fe157506000919050565b816020015151606014612ff657506000919050565b8160200151806020019051810190612aa39190614597565b60008160400151516002148061302957508160400151516003145b61303557506000919050565b81602001515160201461304a57506000919050565b506001919050565b600081604001515160011480613029575081604001515160021461303557506000919050565b6040810151516000901561308e57506000919050565b6020826020015151101561304a57506000919050565b81818082036130b4575050505050565b6000856130da60026130c6888861446c565b6130d09190614640565b6112c0908861456f565b815181106130ea576130ea613e6a565b60200260200101516000015190505b818313613236575b808661310c85612686565b8151811061311c5761311c613e6a565b60200260200101516000015112156131405782613138816148a6565b935050613101565b8561314a83612686565b8151811061315a5761315a613e6a565b60200260200101516000015181121561317f5781613177816148be565b925050613140565b818313613231578561319083612686565b815181106131a0576131a0613e6a565b6020026020010151866131b285612686565b815181106131c2576131c2613e6a565b6020026020010151876131d486612686565b815181106131e4576131e4613e6a565b60200260200101886131f586612686565b8151811061320557613205613e6a565b602002602001018290528290525050828061321f906148a6565b935050818061322d906148be565b9250505b6130f9565b81851215613249576132498686846130a4565b8383121561325c5761325c8684866130a4565b505050505050565b6000670de0b6b3a764000061327983856147e8565b6102b49190614640565b600081613279670de0b6b3a7640000856147e8565b60008060008360020b126132b8576132b3600284900b612686565b6132c8565b6132c86112c0600285900b614493565b90506132e36112c06132dd620d89e7196148db565b60020b90565b8111156133165760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401610397565b60008160011660000361332d57600160801b61333f565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561337e576080613379826ffff97272373d413259a46990580e213a614859565b901c90505b60048216156133a85760806133a3826ffff2e50f5f656932ef12357cf3c7fdcc614859565b901c90505b60088216156133d25760806133cd826fffe5caca7e10e4e61c3624eaa0941cd0614859565b901c90505b60108216156133fc5760806133f7826fffcb9843d60f6159c9db58835c926644614859565b901c90505b6020821615613426576080613421826fff973b41fa98c081472e6896dfb254c0614859565b901c90505b604082161561345057608061344b826fff2ea16466c96a3843ec78b326b52861614859565b901c90505b608082161561347a576080613475826ffe5dee046a99a2a811c461f1969c3053614859565b901c90505b6101008216156134a55760806134a0826ffcbe86c7900a88aedcffc83b479aa3a4614859565b901c90505b6102008216156134d05760806134cb826ff987a7253ac413176f2b074cf7815e54614859565b901c90505b6104008216156134fb5760806134f6826ff3392b0822b70005940c7a398e4b70f3614859565b901c90505b610800821615613526576080613521826fe7159475a2c29b7443b29c7fa6e889d9614859565b901c90505b61100082161561355157608061354c826fd097f3bdfd2022b8845ad8f792aa5825614859565b901c90505b61200082161561357c576080613577826fa9f746462d870fdf8a65dc1f90e061e5614859565b901c90505b6140008216156135a75760806135a2826f70d869a156d2a1b890bb3df62baf32f7614859565b901c90505b6180008216156135d25760806135cd826f31be135f97d08fd981231505542fcfa6614859565b901c90505b620100008216156135fe5760806135f9826f09aa508b5b7a84e1c677de54f3e99bc9614859565b901c90505b62020000821615613629576080613624826e5d6af8dedb81196699c329225ee604614859565b901c90505b6204000082161561365357608061364e826d2216e584f5fa1ea926041bedfe98614859565b901c90505b6208000082161561367b576080613676826b048a170391f7dc42444e8fa2614859565b901c90505b60008460020b131561369657613693816000196147c0565b90505b6102ce6136a8640100000000836147d4565b156136b45760016136b7565b60005b6136c89060ff16602084901c6147ad565b6139ba565b6000808060001985870985870292508281108382030391505080600003613749576000841161373e5760405162461bcd60e51b815260206004820152601960248201527f48616e646c65206e6f6e2d6f766572666c6f77206361736573000000000000006044820152606401610397565b5082900490506102b4565b8084116137985760405162461bcd60e51b815260206004820152601960248201527f70726576656e74732064656e6f6d696e61746f72203d3d2030000000000000006044820152606401610397565b60008486880980840393811190920391905060006137d06137b887612569565b6137c188612569565b6137ca90614493565b16612686565b9586900495938490049360008190030460010190506137ef8184614859565b909317926000613800876003614859565b600218905061380f8188614859565b61381a9060026140a7565b6138249082614859565b90506138308188614859565b61383b9060026140a7565b6138459082614859565b90506138518188614859565b61385c9060026140a7565b6138669082614859565b90506138728188614859565b61387d9060026140a7565b6138879082614859565b90506138938188614859565b61389e9060026140a7565b6138a89082614859565b90506138b48188614859565b6138bf9060026140a7565b6138c99082614859565b90506138d58186614859565b9998505050505050505050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b1790529051600091829182916001600160a01b0387169161394391906148fd565b6000604051808303816000865af19150503d8060008114613980576040519150601f19603f3d011682016040523d82523d6000602084013e613985565b606091505b50915091508161399a57600092505050610116565b80516000036139ae57600092505050610116565b60200151949350505050565b60006001600160a01b038211156125295760405163dccde8ed60e01b815260040160405180910390fd5b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054828255906000526020600020908101928215613a47579160200282015b82811115613a47578251825591602001919060010190613a2c565b506125299291505b808211156125295760008155600101613a4f565b600060208284031215613a7557600080fd5b5035919050565b8151815260208083015190820152604080830151908201526060808301519082015260808101610116565b634e487b7160e01b600052602160045260246000fd5b600a8110613acd57613acd613aa7565b9052565b60005b83811015613aec578181015183820152602001613ad4565b50506000910152565b60008151808452613b0d816020860160208601613ad1565b601f01601f19169290920160200192915050565b60006020808352613b358184018551613abd565b8084015160606040850152613b4d6080850182613af5565b6040860151858203601f19016060870152805180835290840192506000918401905b80831015613b8f5783518252928401926001929092019190840190613b6f565b509695505050505050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613bd357613bd3613b9a565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613c0257613c02613b9a565b604052919050565b600067ffffffffffffffff821115613c2457613c24613b9a565b5060051b60200190565b600082601f830112613c3f57600080fd5b81356020613c54613c4f83613c0a565b613bd9565b8083825260208201915060208460051b870101935086841115613c7657600080fd5b602086015b84811015613b8f5780358352918301918301613c7b565b600080600060608486031215613ca757600080fd5b8335600a8110613cb657600080fd5b925060208481013567ffffffffffffffff80821115613cd457600080fd5b818701915087601f830112613ce857600080fd5b813581811115613cfa57613cfa613b9a565b613d0c601f8201601f19168501613bd9565b8181528985838601011115613d2057600080fd5b818585018683013760009181019094015291935060408601359180831115613d4757600080fd5b5050613d5586828701613c2e565b9150509250925092565b600080600060608486031215613d7457600080fd5b83359250602084013567ffffffffffffffff80821115613d9357600080fd5b613d9f87838801613c2e565b93506040860135915080821115613db557600080fd5b50613d5586828701613c2e565b600181811c90821680613dd657607f821691505b602082108103611d0757634e487b7160e01b600052602260045260246000fd5b60008151808452602080850194506020840160005b83811015613e2757815187529582019590820190600101613e0b565b509495945050505050565b848152613e426020820185613abd565b608060408201526000613e586080830185613af5565b828103606084015261189a8185613df6565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613e9257600080fd5b8151600981106102b457600080fd5b6020810160098310613eb557613eb5613aa7565b91905290565b6001600160a01b0381168114613ed057600080fd5b50565b600060208284031215613ee557600080fd5b81516102b481613ebb565b608080825285518282018190526000919060209060a0850190828a01855b82811015613f5257613f42848351805182526020810151602083015260408101516040830152606081015160608301525050565b9285019290840190600101613f0e565b5050508481036020860152613f678189613af5565b925050508281036040840152613f7d8186613df6565b9050828103606084015261189a8185613df6565b600060808284031215613fa357600080fd5b613fab613bb0565b825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b805160ff8116811461200457600080fd5b600080600060608486031215613ffd57600080fd5b835161400881613ebb565b6020850151909350915061401e60408501613fd7565b90509250925092565b805169ffffffffffffffffffff8116811461200457600080fd5b600080600080600060a0868803121561405957600080fd5b61406286614027565b945060208601519350604086015192506060860151915061408560808701614027565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011657610116614091565b60008060008060008060c087890312156140d357600080fd5b86516140de81613ebb565b60208801519096506140ef81613ebb565b94506140fd60408801613fd7565b935061410b60608801613fd7565b9250608087015161411b81613ebb565b60a088015190925063ffffffff8116811461413557600080fd5b809150509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561418157835163ffffffff168352928401929184019160010161415f565b50909695505050505050565b600082601f83011261419e57600080fd5b815160206141ae613c4f83613c0a565b8083825260208201915060208460051b8701019350868411156141d057600080fd5b602086015b84811015613b8f5780516141e881613ebb565b83529183019183016141d5565b6000806040838503121561420857600080fd5b825167ffffffffffffffff8082111561422057600080fd5b818501915085601f83011261423457600080fd5b81516020614244613c4f83613c0a565b82815260059290921b8401810191818101908984111561426357600080fd5b948201945b838610156142915785518060060b81146142825760008081fd5b82529482019490820190614268565b918801519196509093505050808211156142aa57600080fd5b506142b78582860161418d565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff8213171561011657610116614091565b634e487b7160e01b600052601260045260246000fd5b60008160060b8360060b8061431b5761431b6142ee565b667fffffffffffff1982146000198214161561433957614339614091565b90059392505050565b600082614351576143516142ee565b500790565b60008160020b627fffff19810361436f5761436f614091565b6000190192915050565b600181815b808511156143b457816000190482111561439a5761439a614091565b808516156143a757918102915b93841c939080029061437e565b509250929050565b6000826143cb57506001610116565b816143d857506000610116565b81600181146143ee57600281146143f857614414565b6001915050610116565b60ff84111561440957614409614091565b50506001821b610116565b5060208310610133831016604e8410600b8410161715614437575081810a610116565b6144418383614379565b806000190482111561445557614455614091565b029392505050565b60006102b460ff8416836143bc565b818103600083128015838313168383128216171561448c5761448c614091565b5092915050565b6000600160ff1b82016144a8576144a8614091565b5060000390565b8051801515811461200457600080fd5b6000806000606084860312156144d457600080fd5b83516144df81613ebb565b6020850151909350915061401e604085016144af565b60006080828403121561450757600080fd5b61450f613bb0565b82518060070b811461452057600080fd5b8152602083015167ffffffffffffffff8116811461453d57600080fd5b60208201526040830151600381900b811461455757600080fd5b60408201526060928301519281019290925250919050565b808201828112600083128015821682158216171561458f5761458f614091565b505092915050565b6000806000606084860312156145ac57600080fd5b83516145b781613ebb565b602085015160409095015190969495509392505050565b60ff8416815267ffffffffffffffff831660208201526060604082015260006145fa6060830184613df6565b95945050505050565b6001600160a01b03831681526040602082018190526000906102ce90830184613af5565b60006020828403121561463957600080fd5b5051919050565b60008261464f5761464f6142ee565b600160ff1b82146000198414161561466957614669614091565b500590565b6146788185613abd565b60606020820152600061468e6060830185613af5565b8281036040840152610f4f8185613df6565b601f8211156146e8576000816000526020600020601f850160051c810160208610156146c95750805b601f850160051c820191505b8181101561325c578281556001016146d5565b505050565b815167ffffffffffffffff81111561470757614707613b9a565b61471b816147158454613dc2565b846146a0565b602080601f83116001811461475057600084156147385750858301515b600019600386901b1c1916600185901b17855561325c565b600085815260208120601f198616915b8281101561477f57888601518255948401946001909101908401614760565b508582101561479d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082018082111561011657610116614091565b6000826147cf576147cf6142ee565b500490565b6000826147e3576147e36142ee565b500690565b80820260008212600160ff1b8414161561480457614804614091565b818105831482151761011657610116614091565b600069ffffffffffffffffffff82168061436f5761436f614091565b60006001820161484657614846614091565b5060010190565b60006102b483836143bc565b808202811582820484141761011657610116614091565b60006020828403121561488257600080fd5b6102b4826144af565b60006020828403121561489d57600080fd5b6102b482613fd7565b60006001600160ff1b01820161484657614846614091565b6000600160ff1b82016148d3576148d3614091565b506000190190565b60008160020b627fffff1981036148f4576148f4614091565b60000392915050565b6000825161490f818460208701613ad1565b919091019291505056fea264697066735822122074f32fef384fdc296b0859f1c1f941c8e736c6cb972aa9e2b894956ebd6a80b364736f6c63430008160033","storage":{}},"0x83a0444b93927c3afcbe46e522280390f748e171":{"nonce":1,"balance":"0x0","code":"0x6080604052366100135761001161001d565b005b61001b61001d565b005b6000610027610093565b90503660008037600080366000845af43d6000803e806000811461004a573d6000f35b3d6000fd5b600080823b905060008111915050919050565b6000806040516020016100749061017a565b6040516020818303038152906040528051906020012090508091505090565b600061009d6100c6565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000806040516020016100d89061020c565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006101646023836100f7565b915061016f82610108565b604082019050919050565b6000602082019050818103600083015261019381610157565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b60006101f66021836100f7565b91506102018261019a565b604082019050919050565b60006020820190508181036000830152610225816101e9565b905091905056fea2646970667358221220800da1f73cebd5e4afa07496d9bca6b6c4f526bdd3f4014ec15c70fe3a1c441364736f6c63430008110033","storage":{"0x5a648c35a2f5512218b4683cf10e03f5b7c9dc7346e1bf77d304ae97f60f592b":"0x108f53faf774d7c4c56f5bce9ca6e605ce8aeadd","0x5c7865864a2a990d80b5bb5c40e7b73a029960dc711fbb56120dfab976e92ea3":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266"}},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xc67e2bd3108604cf0168c0e5ef9cd6d78b9bb14b":{"nonce":1,"balance":"0x21e19c6edb7e2445f20","code":"0x","storage":{}},"0xeb045d78d273107348b0300c01d29b7552d622ab":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"nonce":1,"balance":"0x21e19e08b86820a43ea","code":"0x","storage":{}}},"best_block_number":"0x5","blocks":[{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0xcd346446ed010523161f40a5f2b512def549bfb79e165b4354488738416481f2","transactionsRoot":"0xb3a4689832e0b599260ae70362ffcf224b60571b35ff8836904a3d81e2675d66","receiptsRoot":"0x2d13fdc120ab90536fed583939de7fb68b64926a306c1f629593ca9c2c93b198","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x3ea90d","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x2e0b6260","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0x3ea90d","maxFeePerGas":"0x83215600","maxPriorityFeePerGas":"0x3b9aca00","value":"0x0","accessList":[],"input":"0x608060405234801561001057600080fd5b5061494f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80632a952b2d1461005c57806350c946fe14610085578063625ca21c146100a5578063daa250be146100c6578063deba1b98146100d9575b600080fd5b61006f61006a366004613a63565b6100ec565b60405161007c9190613a7c565b60405180910390f35b610098610093366004613a63565b61011c565b60405161007c9190613b21565b6100b86100b3366004613c92565b610276565b60405190815260200161007c565b61006f6100d4366004613d5f565b6102bb565b6100b86100e7366004613c92565b6102d6565b6100f46139e4565b6040805160008082526020820190815281830190925261011691849190610310565b92915050565b6101416040805160608101909152806000815260200160608152602001606081525090565b61014a82610ab6565b60408051606081019091528154909190829060ff16600981111561017057610170613aa7565b600981111561018157610181613aa7565b815260200160018201805461019590613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546101c190613dc2565b801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561026657602002820191906000526020600020905b815481526020019060010190808311610252575b5050505050815250509050919050565b600080604051806060016040528086600981111561029657610296613aa7565b81526020018581526020018481525090506102b081610ac1565b9150505b9392505050565b6102c36139e4565b6102ce848484610310565b949350505050565b60008060405180606001604052808660098111156102f6576102f6613aa7565b81526020018581526020018481525090506102b081610acc565b6103186139e4565b81518351146103a05760408051634bab873760e11b81526004810191909152600d60448201526c72756e74696d6556616c75657360981b606482015260806024820152602260848201527f6d7573742062652073616d65206c656e6774682061732072756e74696d654b6560a482015261797360f01b60c482015260e4015b60405180910390fd5b60006103ab85610c26565b805490915060ff1660018160098111156103c7576103c7613aa7565b036104755761046c6103da838787610c84565b8360010180546103e990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461041590613dc2565b80156104625780601f1061043757610100808354040283529160200191610462565b820191906000526020600020905b81548152906001019060200180831161044557829003601f168201915b5050505050610d46565b925050506102b4565b600281600981111561048957610489613aa7565b036105305761046c61049c838787610c84565b8360010180546104ab90613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546104d790613dc2565b80156105245780601f106104f957610100808354040283529160200191610524565b820191906000526020600020905b81548152906001019060200180831161050757829003601f168201915b50505050508787610ebb565b600381600981111561054457610544613aa7565b036105de5761046c82600101805461055b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461058790613dc2565b80156105d45780601f106105a9576101008083540402835291602001916105d4565b820191906000526020600020905b8154815290600101906020018083116105b757829003601f168201915b5050505050610f59565b60048160098111156105f2576105f2613aa7565b0361068c5761046c82600101805461060990613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461063590613dc2565b80156106825780601f1061065757610100808354040283529160200191610682565b820191906000526020600020905b81548152906001019060200180831161066557829003601f168201915b5050505050611087565b60058160098111156106a0576106a0613aa7565b0361073a5761046c8260010180546106b790613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546106e390613dc2565b80156107305780601f1061070557610100808354040283529160200191610730565b820191906000526020600020905b81548152906001019060200180831161071357829003601f168201915b505050505061131e565b600981600981111561074e5761074e613aa7565b036107ea5761046c82600101805461076590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461079190613dc2565b80156107de5780601f106107b3576101008083540402835291602001916107de565b820191906000526020600020905b8154815290600101906020018083116107c157829003601f168201915b505050505086866114b5565b60068160098111156107fe576107fe613aa7565b036108a35761046c610811838787610c84565b83600101805461082090613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461084c90613dc2565b80156108995780601f1061086e57610100808354040283529160200191610899565b820191906000526020600020905b81548152906001019060200180831161087c57829003601f168201915b50505050506115c7565b60078160098111156108b7576108b7613aa7565b036109ec576040805160608101909152825461046c91908490829060ff1660098111156108e6576108e6613aa7565b60098111156108f7576108f7613aa7565b815260200160018201805461090b90613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461093790613dc2565b80156109845780601f1061095957610100808354040283529160200191610984565b820191906000526020600020905b81548152906001019060200180831161096757829003601f168201915b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109dc57602002820191906000526020600020905b8154815260200190600101908083116109c8575b5050505050815250508686611728565b6008816009811115610a0057610a00613aa7565b03610a9a5761046c826001018054610a1790613dc2565b80601f0160208091040260200160405190810160405280929190818152602001828054610a4390613dc2565b8015610a905780601f10610a6557610100808354040283529160200191610a90565b820191906000526020600020905b815481529060010190602001808311610a7357829003601f168201915b50505050506118a5565b6040516323a9bbc960e01b815260048101879052602401610397565b600061011682610c26565b6000610116826118ea565b6000610ad782610ac1565b9050610ae28161192a565b15610b35577fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e81836000015184602001518560400151604051610b289493929190613e32565b60405180910390a1919050565b610b3e82611a8c565b610b5d578160405163382bbbc960e11b81526004016103979190613b21565b60005b826040015151811015610bd957610b9383604001518281518110610b8657610b86613e6a565b602002602001015161192a565b610bd15782604001518181518110610bad57610bad613e6a565b6020026020010151604051632f19f96160e11b815260040161039791815260200190565b600101610b60565b50610be382611c31565b8351602085015160408087015190519395507fcb64985827770858ec421ad26da7e558c757541643036ce44d6b4eb9e8e5dc5e9450610b28938693929190613e32565b604080516020808201839052606082018190527f696f2e73796e7468657469782e6f7261636c652d6d616e616765722e4e6f6465608080840191909152828401949094528251808303909401845260a0909101909152815191012090565b600283015460609067ffffffffffffffff811115610ca457610ca4613b9a565b604051908082528060200260200182016040528015610cdd57816020015b610cca6139e4565b815260200190600190039081610cc25790505b50905060005b6002850154811015610d3e57610d19856002018281548110610d0757610d07613e6a565b90600052602060002001548585610310565b828281518110610d2b57610d2b613e6a565b6020908102919091010152600101610ce3565b509392505050565b610d4e6139e4565b600082806020019051810190610d649190613e80565b90506000816008811115610d7a57610d7a613aa7565b03610d9057610d8884611ca5565b915050610116565b6001816008811115610da457610da4613aa7565b03610db257610d8884611d0d565b6002816008811115610dc657610dc6613aa7565b03610dd457610d8884611d90565b6003816008811115610de857610de8613aa7565b03610df657610d8884611e13565b6004816008811115610e0a57610e0a613aa7565b03610e1857610d8884611ec9565b6005816008811115610e2c57610e2c613aa7565b03610e3a57610d8884612009565b6006816008811115610e4e57610e4e613aa7565b03610e5c57610d88846120e4565b6007816008811115610e7057610e70613aa7565b03610e7e57610d888461220c565b6008816008811115610e9257610e92613aa7565b03610ea057610d88846122ce565b80604051631be413d360e11b81526004016103979190613ea1565b610ec36139e4565b600084806020019051810190610ed99190613ed3565b604051631ecba7c360e31b81529091506001600160a01b0382169063f65d3e1890610f0e908990899089908990600401613ef0565b608060405180830381865afa158015610f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4f9190613f91565b9695505050505050565b610f616139e4565b600080600084806020019051810190610f7a9190613fe8565b92509250925060008390506000806000836001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fec9190614041565b509350509250925060008660001461100f5761100a8585858a6123c7565b611011565b825b905060128660ff161161103b5761103661102f60ff881660126140a7565b82906124c2565b611053565b61105361104c601260ff89166140a7565b82906124dc565b9050604051806080016040528082815260200183815260200160008152602001600081525098505050505050505050919050565b61108f6139e4565b600080600080600080878060200190518101906110ac91906140ba565b604080516002808252606082018352979d50959b50939950919750955093506000929060208301908036833701905050905081816000815181106110f2576110f2613e6a565b602002602001019063ffffffff16908163ffffffff168152505060008160018151811061112157611121613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526000906001600160a01b0385169063883bdbfd90611165908590600401614143565b600060405180830381865afa158015611182573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111aa91908101906141f5565b5090506000816000815181106111c2576111c2613e6a565b6020026020010151826001815181106111dd576111dd613e6a565b60200260200101516111ef91906142c1565b9050600061121761120563ffffffff87166124f6565b61120f9084614304565b60060b61252d565b905060008260060b12801561124c575061123b63ffffffff8616612569565b612569565b8260060b6112499190614342565b15155b1561125f578061125b81614356565b9150505b600061126d6012600a61445d565b9050600061128061123684848f8f612593565b905060006112908a60ff16612569565b61129c8c60ff16612569565b6112a6919061446c565b905060008082136112d1576112cc6112c56112c084614493565b612686565b84906124dc565b6112e4565b6112e46112dd83612686565b84906124c2565b905060405180608001604052808281526020014281526020016000815260200160008152509e505050505050505050505050505050919050565b6113266139e4565b60008060008480602001905181019061133f91906144bf565b91945092509050826000826113bc576040516396834ad360e01b8152600481018590526001600160a01b038316906396834ad390602401608060405180830381865afa158015611393573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b791906144f5565b611425565b604051639474f45b60e01b8152600481018590526001600160a01b03831690639474f45b90602401608060405180830381865afa158015611401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142591906144f5565b90506000816040015160030b601261143d919061456f565b90506000808213611467576114626114576112c084614493565b845160070b906124dc565b61147e565b61147e61147383612686565b845160070b906124c2565b9050604051806080016040528082815260200184606001518152602001600081526020016000815250975050505050505050919050565b6114bd6139e4565b6000806000868060200190518101906114d69190614597565b92509250925060005b8651811015611545578681815181106114fa576114fa613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b0361153d5785818151811061152f5761152f613e6a565b602002602001015160001c91505b6001016114df565b5060408051600180825281830190925260009160208083019080368337019050509050828160008151811061157c5761157c613e6a565b602002602001018181525050836001838360405160200161159f939291906145ce565b60408051601f198184030181529082905263cf2cabdf60e01b82526103979291600401614603565b6115cf6139e4565b6000828060200190518101906115e59190614627565b90506000846000815181106115fc576115fc613e6a565b602002602001015160000151905060008560018151811061161f5761161f613e6a565b6020026020010151600001519050808214611702576000611653601261164d611648858761446c565b6126a9565b906124c2565b905082158061167b5750611666836126a9565b6116709082614640565b61167985612569565b125b15611700576002875111156116b0578660028151811061169d5761169d613e6a565b6020026020010151945050505050610116565b826000036116d15760405163014cc07160e01b815260040160405180910390fd5b6116da836126a9565b6116e49082614640565b60405163dcac091960e01b815260040161039791815260200190565b505b8560008151811061171557611715613e6a565b6020026020010151935050505092915050565b6117306139e4565b6000846020015180602001905181019061174a9190614627565b905060005b84518110156117bc5784818151811061176a5761176a613e6a565b6020026020010151717374616c656e657373546f6c6572616e636560701b036117b4576117ad8482815181106117a2576117a2613e6a565b602002602001015190565b91506117bc565b60010161174f565b50600085604001516000815181106117d6576117d6613e6a565b6020026020010151905060006117ed828787610310565b60208101519091506117ff84426140a7565b1161180e5792506102b4915050565b86604001515160010361187157866040015160008151811061183257611832613e6a565b602002602001015181600001518260200151604051631808066560e21b8152600401610397939291909283526020830191909152604082015260600190565b61189a876040015160018151811061188b5761188b613e6a565b60200260200101518787610310565b979650505050505050565b6118ad6139e4565b6040518060800160405280838060200190518101906118cc9190614627565b81526020014281526020016000815260200160008152509050919050565b600081600001518260200151836040015160405160200161190d9392919061466e565b604051602081830303815290604052805190602001209050919050565b60008061193683610c26565b60408051606081019091528154909190829060ff16600981111561195c5761195c613aa7565b600981111561196d5761196d613aa7565b815260200160018201805461198190613dc2565b80601f01602080910402602001604051908101604052809291908181526020018280546119ad90613dc2565b80156119fa5780601f106119cf576101008083540402835291602001916119fa565b820191906000526020600020905b8154815290600101906020018083116119dd57829003601f168201915b5050505050815260200160028201805480602002602001604051908101604052809291908181526020018280548015611a5257602002820191906000526020600020905b815481526020019060010190808311611a3e575b505050505081525050905060006009811115611a7057611a70613aa7565b81516009811115611a8357611a83613aa7565b14159392505050565b6000600182516009811115611aa357611aa3613aa7565b1480611ac15750600682516009811115611abf57611abf613aa7565b145b80611ade5750600782516009811115611adc57611adc613aa7565b145b15611aee57611aec826126c1565b505b600182516009811115611b0357611b03613aa7565b03611b11576101168261284a565b600282516009811115611b2657611b26613aa7565b03611b3457610116826128a5565b600382516009811115611b4957611b49613aa7565b03611b575761011682612973565b600482516009811115611b6c57611b6c613aa7565b03611b7a5761011682612aae565b600582516009811115611b8f57611b8f613aa7565b03611b9d5761011682612e92565b600982516009811115611bb257611bb2613aa7565b03611bc05761011682612fcb565b600682516009811115611bd557611bd5613aa7565b03611be3576101168261300e565b600782516009811115611bf857611bf8613aa7565b03611c065761011682613052565b600882516009811115611c1b57611c1b613aa7565b03611c295761011682613078565b506000919050565b600080611c3d836118ea565b9050611c4881610c26565b8351815491935090839060ff19166001836009811115611c6a57611c6a613aa7565b021790555060208301516001830190611c8390826146ed565b5060408301518051611c9f916002850191602090910190613a0c565b50915091565b611cad6139e4565b60005b8251811015611d07578160200151838281518110611cd057611cd0613e6a565b6020026020010151602001511115611cff57828181518110611cf457611cf4613e6a565b602002602001015191505b600101611cb0565b50919050565b611d156139e4565b81600081518110611d2857611d28613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611d5957611d59613e6a565b6020026020010151600001511215611d8857828181518110611d7d57611d7d613e6a565b602002602001015191505b600101611d39565b611d986139e4565b81600081518110611dab57611dab613e6a565b602002602001015190506000600190505b8251811015611d07578160000151838281518110611ddc57611ddc613e6a565b6020026020010151600001511315611e0b57828181518110611e0057611e00613e6a565b602002602001015191505b600101611dbc565b611e1b6139e4565b60005b8251811015611e9557828181518110611e3957611e39613e6a565b60200260200101516000015182600001818151611e56919061456f565b9052508251839082908110611e6d57611e6d613e6a565b60200260200101516020015182602001818151611e8a91906147ad565b905250600101611e1e565b50611ea08251612569565b8151611eac9190614640565b815281516020820151611ebf91906147c0565b6020820152919050565b611ed16139e4565b611eed826000611ee86001865161123691906140a7565b6130a4565b60028251611efb91906147d4565b600003611fd65760408051600280825260608201909252600091816020015b611f226139e4565b815260200190600190039081611f1a57905050905082600160028551611f4891906147c0565b611f5291906140a7565b81518110611f6257611f62613e6a565b602002602001015181600081518110611f7d57611f7d613e6a565b60200260200101819052508260028451611f9791906147c0565b81518110611fa757611fa7613e6a565b602002602001015181600181518110611fc257611fc2613e6a565b60200260200101819052506102b481611e13565b8160028351611fe591906147c0565b81518110611ff557611ff5613e6a565b60200260200101519050919050565b919050565b6120116139e4565b8160008151811061202457612024613e6a565b60209081029190910101515181528151829060009061204557612045613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061207657612076613e6a565b6020026020010151600001518260000181815161209391906147e8565b90525082518390829081106120aa576120aa613e6a565b602002602001015160200151826020018181516120c791906147ad565b90525060010161205b565b5081518160200151611ebf91906147c0565b6120ec6139e4565b816000815181106120ff576120ff613e6a565b60209081029190910101515181528151829060009061212057612120613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061215157612151613e6a565b60200260200101516000015160000361219e5782818151811061217657612176613e6a565b6020026020010151600001516040516338ee04a760e01b815260040161039791815260200190565b8281815181106121b0576121b0613e6a565b602002602001015160000151826000018181516121cd9190614640565b90525082518390829081106121e4576121e4613e6a565b6020026020010151602001518260200181815161220191906147ad565b905250600101612136565b6122146139e4565b8160008151811061222757612227613e6a565b60209081029190910101515181528151829060009061224857612248613e6a565b6020908102919091018101518101519082015260015b82518110156120d25761229083828151811061227c5761227c613e6a565b602090810291909101015151835190613264565b825282518390829081106122a6576122a6613e6a565b602002602001015160200151826020018181516122c391906147ad565b90525060010161225e565b6122d66139e4565b816000815181106122e9576122e9613e6a565b60209081029190910101515181528151829060009061230a5761230a613e6a565b6020908102919091018101518101519082015260015b82518110156120d25782818151811061233b5761233b613e6a565b6020026020010151600001516000036123605782818151811061217657612176613e6a565b61238983828151811061237557612375613e6a565b602090810291909101015151835190613283565b8252825183908290811061239f5761239f613e6a565b602002602001015160200151826020018181516123bc91906147ad565b905250600101612320565b6000826001826123d785426140a7565b90505b69ffffffffffffffffffff8716156124a3576001600160a01b038816639a6fc8f561240489614818565b6040516001600160e01b031960e084901b16815269ffffffffffffffffffff8216600482015290995060240160a060405180830381865afa925050508015612469575060408051601f3d908101601f1916820190925261246691810190614041565b60015b156124a357858210156124805750505050506124a3565b61248a848961456f565b97508661249681614834565b97505050505050506123da565b6124ac82612569565b6124b69084614640565b98975050505050505050565b60006124d261123683600a61484d565b6102b490846147e8565b60006124ec61123683600a61484d565b6102b49084614640565b6000667fffffffffffff66ffffffffffffff83161115612529576040516329d2678160e21b815260040160405180910390fd5b5090565b6000627fffff19600683900b128061254b5750627fffff600683900b135b1561252957604051630d962f7960e21b815260040160405180910390fd5b60006001600160ff1b038211156125295760405163677c430560e11b815260040160405180910390fd5b60008061259f86613298565b90506fffffffffffffffffffffffffffffffff6001600160a01b0382161161261c5760006125d66001600160a01b03831680614859565b9050836001600160a01b0316856001600160a01b03161061260557612600600160c01b87836136cd565b612614565b6126148187600160c01b6136cd565b92505061267d565b600061263b6001600160a01b03831680680100000000000000006136cd565b9050836001600160a01b0316856001600160a01b03161061266a57612665600160801b87836136cd565b612679565b6126798187600160801b6136cd565b9250505b50949350505050565b6000808212156125295760405163029f024d60e31b815260040160405180910390fd5b600080821215612529576126bc82614493565b610116565b6000805b8260400151518110156128415760006126fa846040015183815181106126ed576126ed613e6a565b6020026020010151610ab6565b60408051606081019091528154909190829060ff16600981111561272057612720613aa7565b600981111561273157612731613aa7565b815260200160018201805461274590613dc2565b80601f016020809104026020016040519081016040528092919081815260200182805461277190613dc2565b80156127be5780601f10612793576101008083540402835291602001916127be565b820191906000526020600020905b8154815290600101906020018083116127a157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561281657602002820191906000526020600020905b815481526020019060010190808311612802575b505050505081525050905061282a81611a8c565b612838575060009392505050565b506001016126c5565b50600192915050565b60006002826040015151101561286257506000919050565b81602001515160201461287757506000919050565b600082602001518060200190518101906128919190614627565b905060088111156128415750600092915050565b6000602082602001515110156128bd57506000919050565b600082602001518060200190518101906128d79190613ed3565b90506128ea816306e7ea3960e21b6138e2565b6128f75750600092915050565b604051633b70a5bf60e21b81526001600160a01b0382169063edc296fc90612923908690600401613b21565b6020604051808303816000875af1158015612942573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129669190614870565b6128415750600092915050565b6040810151516000901561298957506000919050565b81602001515160601461299e57506000919050565b60008083602001518060200190518101906129b99190613fe8565b92505091506000829050806001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612a01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a259190614041565b5050505050806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061488b565b60ff168260ff1614612aa357506000949350505050565b506001949350505050565b60408101515160009015612ac457506000919050565b81602001515160c014612ad957506000919050565b6000806000806000808760200151806020019051810190612afa91906140ba565b9550955095509550955095508360ff16866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6c919061488b565b60ff1614612b8257506000979650505050505050565b8260ff16856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be8919061488b565b60ff1614612bfe57506000979650505050505050565b6000826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c629190613ed3565b90506000836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc89190613ed3565b9050876001600160a01b0316826001600160a01b0316148015612cfc5750866001600160a01b0316816001600160a01b0316145b158015612d385750866001600160a01b0316826001600160a01b0316148015612d365750876001600160a01b0316816001600160a01b0316145b155b15612d4d575060009998505050505050505050565b60128660ff161180612d62575060128560ff16115b15612d77575060009998505050505050505050565b8263ffffffff16600003612d95575060009998505050505050505050565b6040805160028082526060820183526000926020830190803683370190505090508381600081518110612dca57612dca613e6a565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110612df957612df9613e6a565b63ffffffff9092166020928302919091019091015260405163883bdbfd60e01b81526001600160a01b0386169063883bdbfd90612e3a908490600401614143565b600060405180830381865afa158015612e57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7f91908101906141f5565b5060019c9b505050505050505050505050565b60408101515160009015612ea857506000919050565b816020015151606014612ebd57506000919050565b60008060008460200151806020019051810190612eda91906144bf565b919450925090508281612f55576040516396834ad360e01b8152600481018490526001600160a01b038216906396834ad390602401608060405180830381865afa158015612f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f5091906144f5565b612fbe565b604051639474f45b60e01b8152600481018490526001600160a01b03821690639474f45b90602401608060405180830381865afa158015612f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fbe91906144f5565b5060019695505050505050565b60408101515160009015612fe157506000919050565b816020015151606014612ff657506000919050565b8160200151806020019051810190612aa39190614597565b60008160400151516002148061302957508160400151516003145b61303557506000919050565b81602001515160201461304a57506000919050565b506001919050565b600081604001515160011480613029575081604001515160021461303557506000919050565b6040810151516000901561308e57506000919050565b6020826020015151101561304a57506000919050565b81818082036130b4575050505050565b6000856130da60026130c6888861446c565b6130d09190614640565b6112c0908861456f565b815181106130ea576130ea613e6a565b60200260200101516000015190505b818313613236575b808661310c85612686565b8151811061311c5761311c613e6a565b60200260200101516000015112156131405782613138816148a6565b935050613101565b8561314a83612686565b8151811061315a5761315a613e6a565b60200260200101516000015181121561317f5781613177816148be565b925050613140565b818313613231578561319083612686565b815181106131a0576131a0613e6a565b6020026020010151866131b285612686565b815181106131c2576131c2613e6a565b6020026020010151876131d486612686565b815181106131e4576131e4613e6a565b60200260200101886131f586612686565b8151811061320557613205613e6a565b602002602001018290528290525050828061321f906148a6565b935050818061322d906148be565b9250505b6130f9565b81851215613249576132498686846130a4565b8383121561325c5761325c8684866130a4565b505050505050565b6000670de0b6b3a764000061327983856147e8565b6102b49190614640565b600081613279670de0b6b3a7640000856147e8565b60008060008360020b126132b8576132b3600284900b612686565b6132c8565b6132c86112c0600285900b614493565b90506132e36112c06132dd620d89e7196148db565b60020b90565b8111156133165760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401610397565b60008160011660000361332d57600160801b61333f565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561337e576080613379826ffff97272373d413259a46990580e213a614859565b901c90505b60048216156133a85760806133a3826ffff2e50f5f656932ef12357cf3c7fdcc614859565b901c90505b60088216156133d25760806133cd826fffe5caca7e10e4e61c3624eaa0941cd0614859565b901c90505b60108216156133fc5760806133f7826fffcb9843d60f6159c9db58835c926644614859565b901c90505b6020821615613426576080613421826fff973b41fa98c081472e6896dfb254c0614859565b901c90505b604082161561345057608061344b826fff2ea16466c96a3843ec78b326b52861614859565b901c90505b608082161561347a576080613475826ffe5dee046a99a2a811c461f1969c3053614859565b901c90505b6101008216156134a55760806134a0826ffcbe86c7900a88aedcffc83b479aa3a4614859565b901c90505b6102008216156134d05760806134cb826ff987a7253ac413176f2b074cf7815e54614859565b901c90505b6104008216156134fb5760806134f6826ff3392b0822b70005940c7a398e4b70f3614859565b901c90505b610800821615613526576080613521826fe7159475a2c29b7443b29c7fa6e889d9614859565b901c90505b61100082161561355157608061354c826fd097f3bdfd2022b8845ad8f792aa5825614859565b901c90505b61200082161561357c576080613577826fa9f746462d870fdf8a65dc1f90e061e5614859565b901c90505b6140008216156135a75760806135a2826f70d869a156d2a1b890bb3df62baf32f7614859565b901c90505b6180008216156135d25760806135cd826f31be135f97d08fd981231505542fcfa6614859565b901c90505b620100008216156135fe5760806135f9826f09aa508b5b7a84e1c677de54f3e99bc9614859565b901c90505b62020000821615613629576080613624826e5d6af8dedb81196699c329225ee604614859565b901c90505b6204000082161561365357608061364e826d2216e584f5fa1ea926041bedfe98614859565b901c90505b6208000082161561367b576080613676826b048a170391f7dc42444e8fa2614859565b901c90505b60008460020b131561369657613693816000196147c0565b90505b6102ce6136a8640100000000836147d4565b156136b45760016136b7565b60005b6136c89060ff16602084901c6147ad565b6139ba565b6000808060001985870985870292508281108382030391505080600003613749576000841161373e5760405162461bcd60e51b815260206004820152601960248201527f48616e646c65206e6f6e2d6f766572666c6f77206361736573000000000000006044820152606401610397565b5082900490506102b4565b8084116137985760405162461bcd60e51b815260206004820152601960248201527f70726576656e74732064656e6f6d696e61746f72203d3d2030000000000000006044820152606401610397565b60008486880980840393811190920391905060006137d06137b887612569565b6137c188612569565b6137ca90614493565b16612686565b9586900495938490049360008190030460010190506137ef8184614859565b909317926000613800876003614859565b600218905061380f8188614859565b61381a9060026140a7565b6138249082614859565b90506138308188614859565b61383b9060026140a7565b6138459082614859565b90506138518188614859565b61385c9060026140a7565b6138669082614859565b90506138728188614859565b61387d9060026140a7565b6138879082614859565b90506138938188614859565b61389e9060026140a7565b6138a89082614859565b90506138b48188614859565b6138bf9060026140a7565b6138c99082614859565b90506138d58186614859565b9998505050505050505050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b1790529051600091829182916001600160a01b0387169161394391906148fd565b6000604051808303816000865af19150503d8060008114613980576040519150601f19603f3d011682016040523d82523d6000602084013e613985565b606091505b50915091508161399a57600092505050610116565b80516000036139ae57600092505050610116565b60200151949350505050565b60006001600160a01b038211156125295760405163dccde8ed60e01b815260040160405180910390fd5b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054828255906000526020600020908101928215613a47579160200282015b82811115613a47578251825591602001919060010190613a2c565b506125299291505b808211156125295760008155600101613a4f565b600060208284031215613a7557600080fd5b5035919050565b8151815260208083015190820152604080830151908201526060808301519082015260808101610116565b634e487b7160e01b600052602160045260246000fd5b600a8110613acd57613acd613aa7565b9052565b60005b83811015613aec578181015183820152602001613ad4565b50506000910152565b60008151808452613b0d816020860160208601613ad1565b601f01601f19169290920160200192915050565b60006020808352613b358184018551613abd565b8084015160606040850152613b4d6080850182613af5565b6040860151858203601f19016060870152805180835290840192506000918401905b80831015613b8f5783518252928401926001929092019190840190613b6f565b509695505050505050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613bd357613bd3613b9a565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613c0257613c02613b9a565b604052919050565b600067ffffffffffffffff821115613c2457613c24613b9a565b5060051b60200190565b600082601f830112613c3f57600080fd5b81356020613c54613c4f83613c0a565b613bd9565b8083825260208201915060208460051b870101935086841115613c7657600080fd5b602086015b84811015613b8f5780358352918301918301613c7b565b600080600060608486031215613ca757600080fd5b8335600a8110613cb657600080fd5b925060208481013567ffffffffffffffff80821115613cd457600080fd5b818701915087601f830112613ce857600080fd5b813581811115613cfa57613cfa613b9a565b613d0c601f8201601f19168501613bd9565b8181528985838601011115613d2057600080fd5b818585018683013760009181019094015291935060408601359180831115613d4757600080fd5b5050613d5586828701613c2e565b9150509250925092565b600080600060608486031215613d7457600080fd5b83359250602084013567ffffffffffffffff80821115613d9357600080fd5b613d9f87838801613c2e565b93506040860135915080821115613db557600080fd5b50613d5586828701613c2e565b600181811c90821680613dd657607f821691505b602082108103611d0757634e487b7160e01b600052602260045260246000fd5b60008151808452602080850194506020840160005b83811015613e2757815187529582019590820190600101613e0b565b509495945050505050565b848152613e426020820185613abd565b608060408201526000613e586080830185613af5565b828103606084015261189a8185613df6565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613e9257600080fd5b8151600981106102b457600080fd5b6020810160098310613eb557613eb5613aa7565b91905290565b6001600160a01b0381168114613ed057600080fd5b50565b600060208284031215613ee557600080fd5b81516102b481613ebb565b608080825285518282018190526000919060209060a0850190828a01855b82811015613f5257613f42848351805182526020810151602083015260408101516040830152606081015160608301525050565b9285019290840190600101613f0e565b5050508481036020860152613f678189613af5565b925050508281036040840152613f7d8186613df6565b9050828103606084015261189a8185613df6565b600060808284031215613fa357600080fd5b613fab613bb0565b825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b805160ff8116811461200457600080fd5b600080600060608486031215613ffd57600080fd5b835161400881613ebb565b6020850151909350915061401e60408501613fd7565b90509250925092565b805169ffffffffffffffffffff8116811461200457600080fd5b600080600080600060a0868803121561405957600080fd5b61406286614027565b945060208601519350604086015192506060860151915061408560808701614027565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b8181038181111561011657610116614091565b60008060008060008060c087890312156140d357600080fd5b86516140de81613ebb565b60208801519096506140ef81613ebb565b94506140fd60408801613fd7565b935061410b60608801613fd7565b9250608087015161411b81613ebb565b60a088015190925063ffffffff8116811461413557600080fd5b809150509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561418157835163ffffffff168352928401929184019160010161415f565b50909695505050505050565b600082601f83011261419e57600080fd5b815160206141ae613c4f83613c0a565b8083825260208201915060208460051b8701019350868411156141d057600080fd5b602086015b84811015613b8f5780516141e881613ebb565b83529183019183016141d5565b6000806040838503121561420857600080fd5b825167ffffffffffffffff8082111561422057600080fd5b818501915085601f83011261423457600080fd5b81516020614244613c4f83613c0a565b82815260059290921b8401810191818101908984111561426357600080fd5b948201945b838610156142915785518060060b81146142825760008081fd5b82529482019490820190614268565b918801519196509093505050808211156142aa57600080fd5b506142b78582860161418d565b9150509250929050565b600682810b9082900b03667fffffffffffff198112667fffffffffffff8213171561011657610116614091565b634e487b7160e01b600052601260045260246000fd5b60008160060b8360060b8061431b5761431b6142ee565b667fffffffffffff1982146000198214161561433957614339614091565b90059392505050565b600082614351576143516142ee565b500790565b60008160020b627fffff19810361436f5761436f614091565b6000190192915050565b600181815b808511156143b457816000190482111561439a5761439a614091565b808516156143a757918102915b93841c939080029061437e565b509250929050565b6000826143cb57506001610116565b816143d857506000610116565b81600181146143ee57600281146143f857614414565b6001915050610116565b60ff84111561440957614409614091565b50506001821b610116565b5060208310610133831016604e8410600b8410161715614437575081810a610116565b6144418383614379565b806000190482111561445557614455614091565b029392505050565b60006102b460ff8416836143bc565b818103600083128015838313168383128216171561448c5761448c614091565b5092915050565b6000600160ff1b82016144a8576144a8614091565b5060000390565b8051801515811461200457600080fd5b6000806000606084860312156144d457600080fd5b83516144df81613ebb565b6020850151909350915061401e604085016144af565b60006080828403121561450757600080fd5b61450f613bb0565b82518060070b811461452057600080fd5b8152602083015167ffffffffffffffff8116811461453d57600080fd5b60208201526040830151600381900b811461455757600080fd5b60408201526060928301519281019290925250919050565b808201828112600083128015821682158216171561458f5761458f614091565b505092915050565b6000806000606084860312156145ac57600080fd5b83516145b781613ebb565b602085015160409095015190969495509392505050565b60ff8416815267ffffffffffffffff831660208201526060604082015260006145fa6060830184613df6565b95945050505050565b6001600160a01b03831681526040602082018190526000906102ce90830184613af5565b60006020828403121561463957600080fd5b5051919050565b60008261464f5761464f6142ee565b600160ff1b82146000198414161561466957614669614091565b500590565b6146788185613abd565b60606020820152600061468e6060830185613af5565b8281036040840152610f4f8185613df6565b601f8211156146e8576000816000526020600020601f850160051c810160208610156146c95750805b601f850160051c820191505b8181101561325c578281556001016146d5565b505050565b815167ffffffffffffffff81111561470757614707613b9a565b61471b816147158454613dc2565b846146a0565b602080601f83116001811461475057600084156147385750858301515b600019600386901b1c1916600185901b17855561325c565b600085815260208120601f198616915b8281101561477f57888601518255948401946001909101908401614760565b508582101561479d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082018082111561011657610116614091565b6000826147cf576147cf6142ee565b500490565b6000826147e3576147e36142ee565b500690565b80820260008212600160ff1b8414161561480457614804614091565b818105831482151761011657610116614091565b600069ffffffffffffffffffff82168061436f5761436f614091565b60006001820161484657614846614091565b5060010190565b60006102b483836143bc565b808202811582820484141761011657610116614091565b60006020828403121561488257600080fd5b6102b4826144af565b60006020828403121561489d57600080fd5b6102b482613fd7565b60006001600160ff1b01820161484657614846614091565b6000600160ff1b82016148d3576148d3614091565b506000190190565b60008160020b627fffff1981036148f4576148f4614091565b60000392915050565b6000825161490f818460208701613ad1565b919091019291505056fea264697066735822122074f32fef384fdc296b0859f1c1f941c8e736c6cb972aa9e2b894956ebd6a80b364736f6c63430008160033","r":"0x1","s":"0x1","yParity":"0x0","hash":"0xbc73db80bf4b8784ba10a8910a0b7ef85f6846d102b41dd990969ea205335354"}}],"ommers":[]},{"header":{"parentHash":"0x026ae0c6ae91f186a9befa1ac8be30eea35e30e77de51a731085221e5cd39209","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0xb6003e7ba07a15a9e35f63daa484728ec4ceeded0c4d10ac1b04e9552d412b3c","transactionsRoot":"0x6e4969a136061ca7a390d12830d47a151585325a8d396819fb2b958ff85e9f8f","receiptsRoot":"0xc3e81df67d3e2a6c8345a954ef250cfcc41abcc2292a5aa263071124533fc9ad","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x3","gasLimit":"0x1c9c380","gasUsed":"0x3c0f6","timestamp":"0x66b200ce","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x18993a68","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0x3c0f6","maxFeePerGas":"0x5d4285cd","maxPriorityFeePerGas":"0x3b9aca00","value":"0x0","accessList":[],"input":"0x608060405234801561001057600080fd5b50610380806100206000396000f3fe6080604052600080357fffffffff0000000000000000000000000000000000000000000000000000000016905060008160e01c610251565b60006379ba509782101561015e5781631627540c811461009857632a952b2d81146100b457633659cfe681146100d0576350c946fe81146100ec576353a47bb781146101085763625ca21c81146101245763718fe928811461014057610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc9150610158565b738138ef7cf908021d117e542120b7a390650161079150610158565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc91505b5061024c565b816379ba509781146101a657638da5cb5b81146101c25763aaf10f4281146101de5763c7f62cda81146101fa5763daa250be81146102165763deba1b9881146102325761024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b7347d08dad17ccb558b3ea74b1a0e73a9cc804a9dc915061024a565b738138ef7cf908021d117e542120b7a39065016107915061024a565b738138ef7cf908021d117e542120b7a3906501610791505b505b919050565b61025a81610037565b915050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102ce57816040517fc2a825f50000000000000000000000000000000000000000000000000000000081526004016102c5919061032f565b60405180910390fd5b3660008037600080366000845af43d6000803e80600081146102ef573d6000f35b3d6000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610329816102f4565b82525050565b60006020820190506103446000830184610320565b9291505056fea264697066735822122017a4b7fdaaab3897a7b47abaed8d2ee92d558883d3bb2a8454f9601b2ab2c3db64736f6c63430008150033","r":"0x1","s":"0x1","yParity":"0x0","hash":"0x2476e039803622aeb040f924f04c493f559aed3d6c9372ab405cb33c8c695328"}}],"ommers":[]},{"header":{"parentHash":"0x3d22100ac0ee8d5cde334f7f926191a861b0648971ebc179547df28a0224c6d0","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x9511d4711e5c30a72b0bff38a261daa75dcc5ba8b772d970a5c742244b4c861b","transactionsRoot":"0xba5fff578d3d6c2cd63acbe9bca353eaa6fe22a5c408956eff49106e0a96c507","receiptsRoot":"0xbae111f01cb07677e3a8c5031546138407c01bc964d3493d732dc4edf47d36d3","logsBloom":"0x00000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000020000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000001000000000000000000000400000001000010000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x5","gasLimit":"0x1c9c380","gasUsed":"0xcae7","timestamp":"0x66b200cb","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x12e09c7a","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0xcc4d","maxFeePerGas":"0x557e5ec4","maxPriorityFeePerGas":"0x3b9aca00","to":"0x83a0444b93927c3afcbe46e522280390f748e171","value":"0x0","accessList":[],"input":"0x3659cfe6000000000000000000000000108f53faf774d7c4c56f5bce9ca6e605ce8aeadd","r":"0x1","s":"0x1","yParity":"0x0","hash":"0xf88e7b19ee347145c257e0cf7ac4ecc2bae83ca79d7edaa231e71d3213aeb151"}}],"ommers":[]},{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x9c8eaf493f8b4edce2ba1647343eadcc0989cf461e712c0a6253ff2ca1842bb7","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0xdd07c07470e1deff3749831f0f1ad8d4b6e35505e83b3c6ea14181716197cd8a","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x29aa352e71b139e83b397bdd3dcf9b65d74770edaf3a9624d0dbc4f96f868680","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200cb","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x24a1ab52","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200c9","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0xf6930be4847cac5017bbcbec2756eed19f36b4196526a98a88e311c296e3a9be","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x29aa352e71b139e83b397bdd3dcf9b65d74770edaf3a9624d0dbc4f96f868680","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200cc","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x200d75e8","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0xb6003e7ba07a15a9e35f63daa484728ec4ceeded0c4d10ac1b04e9552d412b3c","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x4","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x1592fbf9","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x149d41e3b89d8324cef3feff98ef308e97bafe8745cc8461c60172bc7d4c44ba","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x510f2275449c013534a25ad0b13c867caf720947b68bcbcd4863f7b172a5d023","transactionsRoot":"0x0b44110186e52ff0ceb6b0776ca2992c94144a4ed712eef65ea038260ef0fcc7","receiptsRoot":"0xc2823b8eb4730d9f2657137cc2ddc2c4f22ab68e0ab826236cf6a1551ca2b3a5","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0xe61f9","timestamp":"0x66b200cb","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x342770c0","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0xe94d1","maxFeePerGas":"0x83215600","maxPriorityFeePerGas":"0x3b9aca00","to":"0x4e59b44847b379578588920ca78fbf26c0b4956c","value":"0x0","accessList":[],"input":"0x4786e4342646b3ba97c1790b6cf5a55087a36240b22570f5d3a5d6bcc929d93b608060405234801561001057600080fd5b5060008061002661006d60201b61081b1760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610141565b60008060405160200161007f90610121565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b600061010b60238361009e565b9150610116826100af565b604082019050919050565b6000602082019050818103600083015261013a816100fe565b9050919050565b611000806101506000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c806379ba50971161005b57806379ba5097146100ed5780638da5cb5b146100f7578063aaf10f4214610115578063c7f62cda1461013357610088565b80631627540c1461008d5780633659cfe6146100a957806353a47bb7146100c5578063718fe928146100e3575b600080fd5b6100a760048036038101906100a29190610d25565b61014f565b005b6100c360048036038101906100be9190610d25565b6102d0565b005b6100cd6102e4565b6040516100da9190610d61565b60405180910390f35b6100eb610317565b005b6100f56103fe565b005b6100ff61058b565b60405161010c9190610d61565b60405180910390f35b61011d6105be565b60405161012a9190610d61565b60405180910390f35b61014d60048036038101906101489190610d25565b6105f1565b005b61015761084c565b600061016161081b565b9050600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036101c9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610252576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22826040516102c49190610d61565b60405180910390a15050565b6102d861084c565b6102e1816108c5565b50565b60006102ee61081b565b60010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600061032161081b565b90503373ffffffffffffffffffffffffffffffffffffffff168160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146103b757336040517fa0e5a0d70000000000000000000000000000000000000000000000000000000081526004016103ae9190610d61565b60405180910390fd5b60008160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600061040861081b565b905060008160010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104a357336040517fa0e5a0d700000000000000000000000000000000000000000000000000000000815260040161049a9190610d61565b60405180910390fd5b7fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c8260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16826040516104f8929190610d7c565b60405180910390a1808260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008260010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b600061059561081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105c8610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60006105fb610b05565b905060018160000160146101000a81548160ff02191690831515021790555060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050828260000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008373ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16633659cfe6846040516024016106cc9190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161071b9190610e16565b600060405180830381855af49150503d8060008114610756576040519150601f19603f3d011682016040523d82523d6000602084013e61075b565b606091505b505090508015806107c357508173ffffffffffffffffffffffffffffffffffffffff16610786610b05565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b156107fa576040517fa1cfa5a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360000160146101000a81548160ff0219169083151502179055600080fd5b60008060405160200161082d90610eb0565b6040516020818303038152906040528051906020012090508091505090565b610854610b36565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108c357336040517f8e4a23d60000000000000000000000000000000000000000000000000000000081526004016108ba9190610d61565b60405180910390fd5b565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61093481610b69565b61097557806040517f8a8b41ec00000000000000000000000000000000000000000000000000000000815260040161096c9190610d61565b60405180910390fd5b600061097f610b05565b90508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610a0a576040517fa88ee57700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000160149054906101000a900460ff16158015610a2e5750610a2d82610b7c565b5b15610a7057816040517f15504301000000000000000000000000000000000000000000000000000000008152600401610a679190610d61565b60405180910390fd5b818160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503073ffffffffffffffffffffffffffffffffffffffff167f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c783604051610af99190610d61565b60405180910390a25050565b600080604051602001610b1790610f42565b6040516020818303038152906040528051906020012090508091505090565b6000610b4061081b565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080823b905060008111915050919050565b60008060003073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1663c7f62cda86604051602401610bc59190610d61565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c149190610e16565b600060405180830381855af49150503d8060008114610c4f576040519150601f19603f3d011682016040523d82523d6000602084013e610c54565b606091505b509150915081158015610cb9575063a1cfa5a860e01b604051602001610c7a9190610faf565b6040516020818303038152906040528051906020012081604051602001610ca19190610e16565b60405160208183030381529060405280519060200120145b92505050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cf282610cc7565b9050919050565b610d0281610ce7565b8114610d0d57600080fd5b50565b600081359050610d1f81610cf9565b92915050565b600060208284031215610d3b57610d3a610cc2565b5b6000610d4984828501610d10565b91505092915050565b610d5b81610ce7565b82525050565b6000602082019050610d766000830184610d52565b92915050565b6000604082019050610d916000830185610d52565b610d9e6020830184610d52565b9392505050565b600081519050919050565b600081905092915050565b60005b83811015610dd9578082015181840152602081019050610dbe565b60008484015250505050565b6000610df082610da5565b610dfa8185610db0565b9350610e0a818560208601610dbb565b80840191505092915050565b6000610e228284610de5565b915081905092915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b6000610e9a602383610e2d565b9150610ea582610e3e565b604082019050919050565b60006020820190508181036000830152610ec981610e8d565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b6000610f2c602183610e2d565b9150610f3782610ed0565b604082019050919050565b60006020820190508181036000830152610f5b81610f1f565b9050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610fa9610fa482610f62565b610f8e565b82525050565b6000610fbb8284610f98565b6004820191508190509291505056fea264697066735822122023a7c33d7b91dce35ffbcf8837693364ab22a3905d0fc00016833e5fac45ca2f64736f6c63430008110033","r":"0x1","s":"0x1","yParity":"0x0","hash":"0x4feae6769d748b4f0f7c9bf21d782236c88f13906789a3ec602961296e4c3e43"}}],"ommers":[]},{"header":{"parentHash":"0xb3535af5103fd1c2bbd6dc7ff23f0799037a6542c231ebcb85abd776560fa512","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x23d74fb99ff6e42cbb5c33f92b078e37be6af2b6092459b103ff7059a6517ebc","transactionsRoot":"0x9eab45eca206fe11c107ea985c7d02fcfa442836aea3e04ba11dc4df587d5aa6","receiptsRoot":"0xe25abcfa973db8c55f73292137c626430de130a382ad4466337fefb0f7c8fde0","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x3ce3f","timestamp":"0x66b200cd","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x1c0bc72b","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x343a","nonce":"0x0","gas":"0x3d8a8","maxFeePerGas":"0x6211577c","maxPriorityFeePerGas":"0x3b9aca00","to":"0x4e59b44847b379578588920ca78fbf26c0b4956c","value":"0x0","accessList":[],"input":"0x4786e4342646b3ba97c1790b6cf5a55087a36240b22570f5d3a5d6bcc929d93b608060405234801561001057600080fd5b5060405161068538038061068583398181016040528101906100329190610275565b818181600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361009b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6100ae8161019d60201b61004f1760201c565b6100ef57806040517f8a8b41ec0000000000000000000000000000000000000000000000000000000081526004016100e691906102c4565b60405180910390fd5b806100fe6101b060201b60201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050806101536101e160201b6100621760201c565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050610414565b600080823b905060008111915050919050565b6000806040516020016101c290610362565b6040516020818303038152906040528051906020012090508091505090565b6000806040516020016101f3906103f4565b6040516020818303038152906040528051906020012090508091505090565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061024282610217565b9050919050565b61025281610237565b811461025d57600080fd5b50565b60008151905061026f81610249565b92915050565b6000806040838503121561028c5761028b610212565b5b600061029a85828601610260565b92505060206102ab85828601610260565b9150509250929050565b6102be81610237565b82525050565b60006020820190506102d960008301846102b5565b92915050565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b600061034c6021836102df565b9150610357826102f0565b604082019050919050565b6000602082019050818103600083015261037b8161033f565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006103de6023836102df565b91506103e982610382565b604082019050919050565b6000602082019050818103600083015261040d816103d1565b9050919050565b610262806104236000396000f3fe6080604052366100135761001161001d565b005b61001b61001d565b005b6000610027610093565b90503660008037600080366000845af43d6000803e806000811461004a573d6000f35b3d6000fd5b600080823b905060008111915050919050565b6000806040516020016100749061017a565b6040516020818303038152906040528051906020012090508091505090565b600061009d6100c6565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000806040516020016100d89061020c565b6040516020818303038152906040528051906020012090508091505090565b600082825260208201905092915050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e6160008201527f626c650000000000000000000000000000000000000000000000000000000000602082015250565b60006101646023836100f7565b915061016f82610108565b604082019050919050565b6000602082019050818103600083015261019381610157565b9050919050565b7f696f2e73796e7468657469782e636f72652d636f6e7472616374732e50726f7860008201527f7900000000000000000000000000000000000000000000000000000000000000602082015250565b60006101f66021836100f7565b91506102018261019a565b604082019050919050565b60006020820190508181036000830152610225816101e9565b905091905056fea2646970667358221220800da1f73cebd5e4afa07496d9bca6b6c4f526bdd3f4014ec15c70fe3a1c441364736f6c6343000811003300000000000000000000000047d08dad17ccb558b3ea74b1a0e73a9cc804a9dc000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266","r":"0x1","s":"0x1","yParity":"0x0","hash":"0xb6794d5c7abed6f91d447e8efb72ef2580595a6d7c8dee57ba1dbb330970146a"}}],"ommers":[]},{"header":{"parentHash":"0x08abe6e453727534d8dd708843a7522b7d500338bdfe2402ca105dcdb05eebe9","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x510f2275449c013534a25ad0b13c867caf720947b68bcbcd4863f7b172a5d023","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x3","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66b200ca","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x29dd5614","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]}]} \ No newline at end of file diff --git a/crates/anvil/test-data/state-dump-legacy.json b/crates/anvil/test-data/state-dump-legacy.json index 45906791d..0641b2f7b 100644 --- a/crates/anvil/test-data/state-dump-legacy.json +++ b/crates/anvil/test-data/state-dump-legacy.json @@ -1 +1 @@ -{"block":{"number":"0x2","coinbase":"0x0000000000000000000000000000000000000000","timestamp":"0x66cdc823","gas_limit":"0x1c9c380","basefee":"0x342a1c58","difficulty":"0x0","prevrandao":"0xb92480171c0235f8c6710a4047d7ee14a3be58c630839fb4422826ff3a013e44","blob_excess_gas_and_price":{"excess_blob_gas":0,"blob_gasprice":1}},"accounts":{"0x0000000000000000000000000000000000000000":{"nonce":0,"balance":"0xa410","code":"0x","storage":{}},"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x4e59b44847b379578588920ca78fbf26c0b4956c":{"nonce":0,"balance":"0x0","code":"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3","storage":{}},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"nonce":1,"balance":"0x21e19e0b90393da9b38","code":"0x","storage":{}},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"nonce":1,"balance":"0x21e19e0b6a140b55df8","code":"0x","storage":{}}},"best_block_number":"0x2","blocks":[{"header":{"parentHash":"0xceb0fe420d6f14a8eeec4319515b89acbb0bb4861cad9983d529ab4b1e4af929","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1","transactionsRoot":"0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdc823","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x342a1c58","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gasLimit":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","value":"0x0","accessList":[],"input":"0x","r":"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0","s":"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd","yParity":"0x0","hash":"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"}}],"ommers":[]},{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66cdc80e","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0xa00dc0c9ee9a888e67ea32d8772f8cc28eff62448c9ec985ee941fcbc921ba59","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x6e5f60b37eeaece7dedfc42cc394731a0ae3ed3d3be93c402780b2e23e141175","transactionsRoot":"0x9ceaeb1b16b924afbf4bf4df4c2c49dc9cfbe23ac7a40bf26a704158ea2d352f","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdc814","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gasLimit":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","value":"0x0","accessList":[],"input":"0x","r":"0x703a4b4d6dbff2fa2345df73263df2098faa7214863b5ec82c4c07162d87b853","s":"0x17dea762c4ce600ad1d9d2c9ae6dd35b9e526d03c875f868ad0792fd4fad72e0","yParity":"0x0","hash":"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3"}}],"ommers":[]}]} \ No newline at end of file +{"block":{"number":"0x2","coinbase":"0x0000000000000000000000000000000000000000","timestamp":"0x66cdc823","gas_limit":"0x1c9c380","basefee":"0x342a1c58","difficulty":"0x0","prevrandao":"0xb92480171c0235f8c6710a4047d7ee14a3be58c630839fb4422826ff3a013e44","blob_excess_gas_and_price":{"excess_blob_gas":0,"blob_gasprice":1}},"accounts":{"0x0000000000000000000000000000000000000000":{"nonce":0,"balance":"0xa410","code":"0x","storage":{}},"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x4e59b44847b379578588920ca78fbf26c0b4956c":{"nonce":0,"balance":"0x0","code":"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3","storage":{}},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"nonce":1,"balance":"0x21e19e0b90393da9b38","code":"0x","storage":{}},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"nonce":1,"balance":"0x21e19e0b6a140b55df8","code":"0x","storage":{}}},"best_block_number":"0x2","blocks":[{"header":{"parentHash":"0xceb0fe420d6f14a8eeec4319515b89acbb0bb4861cad9983d529ab4b1e4af929","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1","transactionsRoot":"0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdc823","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x342a1c58","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gas":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","value":"0x0","accessList":[],"input":"0x","r":"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0","s":"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd","yParity":"0x0","hash":"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"}}],"ommers":[]},{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66cdc80e","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0xa00dc0c9ee9a888e67ea32d8772f8cc28eff62448c9ec985ee941fcbc921ba59","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x6e5f60b37eeaece7dedfc42cc394731a0ae3ed3d3be93c402780b2e23e141175","transactionsRoot":"0x9ceaeb1b16b924afbf4bf4df4c2c49dc9cfbe23ac7a40bf26a704158ea2d352f","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdc814","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gas":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","value":"0x0","accessList":[],"input":"0x","r":"0x703a4b4d6dbff2fa2345df73263df2098faa7214863b5ec82c4c07162d87b853","s":"0x17dea762c4ce600ad1d9d2c9ae6dd35b9e526d03c875f868ad0792fd4fad72e0","yParity":"0x0","hash":"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3"}}],"ommers":[]}]} \ No newline at end of file diff --git a/crates/anvil/test-data/state-dump.json b/crates/anvil/test-data/state-dump.json index 159f30d21..3a3c478cf 100644 --- a/crates/anvil/test-data/state-dump.json +++ b/crates/anvil/test-data/state-dump.json @@ -1 +1 @@ -{"block":{"number":"0x2","coinbase":"0x0000000000000000000000000000000000000000","timestamp":"0x66cdcc2b","gas_limit":"0x1c9c380","basefee":"0x342a1c58","difficulty":"0x0","prevrandao":"0xdb639d7f8af4f0ff2aa9cc49861820e72f5f8bfeeed677d1e3569f6b1625df4a","blob_excess_gas_and_price":{"excess_blob_gas":0,"blob_gasprice":1}},"accounts":{"0x0000000000000000000000000000000000000000":{"nonce":0,"balance":"0xa410","code":"0x","storage":{}},"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x4e59b44847b379578588920ca78fbf26c0b4956c":{"nonce":0,"balance":"0x0","code":"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3","storage":{}},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"nonce":1,"balance":"0x21e19e0b90393da9b38","code":"0x","storage":{}},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"nonce":1,"balance":"0x21e19e0b6a140b55df8","code":"0x","storage":{}}},"best_block_number":"0x2","blocks":[{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66cdcc25","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x3a52101c98a4319c419681131d3585d70a6cf13a9af25136be20d451eed5480a","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x6e5f60b37eeaece7dedfc42cc394731a0ae3ed3d3be93c402780b2e23e141175","transactionsRoot":"0x9ceaeb1b16b924afbf4bf4df4c2c49dc9cfbe23ac7a40bf26a704158ea2d352f","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdcc29","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"transaction":{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gasLimit":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","value":"0x0","accessList":[],"input":"0x","r":"0x703a4b4d6dbff2fa2345df73263df2098faa7214863b5ec82c4c07162d87b853","s":"0x17dea762c4ce600ad1d9d2c9ae6dd35b9e526d03c875f868ad0792fd4fad72e0","yParity":"0x0","hash":"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3"}},"impersonated_sender":null}],"ommers":[]},{"header":{"parentHash":"0x0d575f9ca968cd483549172245483a12343afc3cabef80f0fa39855b10b98c70","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1","transactionsRoot":"0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdcc2b","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x342a1c58","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"transaction":{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gasLimit":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","value":"0x0","accessList":[],"input":"0x","r":"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0","s":"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd","yParity":"0x0","hash":"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"}},"impersonated_sender":null}],"ommers":[]}],"transactions":[{"info":{"transaction_hash":"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3","transaction_index":0,"from":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","to":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","contract_address":null,"traces":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","address":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","maybe_precompile":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x","output":"0x","gas_used":0,"gas_limit":1,"status":"Stop","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}],"exit":"Stop","out":"0x","nonce":0,"gas_used":21000},"receipt":{"type":"0x2","status":"0x1","cumulativeGasUsed":"0x5208","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"block_hash":"0x0d575f9ca968cd483549172245483a12343afc3cabef80f0fa39855b10b98c70","block_number":1},{"info":{"transaction_hash":"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515","transaction_index":0,"from":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","to":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","contract_address":null,"traces":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","address":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","maybe_precompile":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x","output":"0x","gas_used":0,"gas_limit":1,"status":"Stop","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}],"exit":"Stop","out":"0x","nonce":0,"gas_used":21000},"receipt":{"type":"0x2","status":"0x1","cumulativeGasUsed":"0x5208","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"block_hash":"0x1f435a603c1bf6d544a90156b572b96d7a1730028422d800839bae78bb3506d0","block_number":2}]} \ No newline at end of file +{"block":{"number":"0x2","coinbase":"0x0000000000000000000000000000000000000000","timestamp":"0x66cdcc2b","gas_limit":"0x1c9c380","basefee":"0x342a1c58","difficulty":"0x0","prevrandao":"0xdb639d7f8af4f0ff2aa9cc49861820e72f5f8bfeeed677d1e3569f6b1625df4a","blob_excess_gas_and_price":{"excess_blob_gas":0,"blob_gasprice":1}},"accounts":{"0x0000000000000000000000000000000000000000":{"nonce":0,"balance":"0xa410","code":"0x","storage":{}},"0x14dc79964da2c08b23698b3d3cc7ca32193d9955":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x4e59b44847b379578588920ca78fbf26c0b4956c":{"nonce":0,"balance":"0x0","code":"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3","storage":{}},"0x70997970c51812dc3a010c7d01b50e0d17dc79c8":{"nonce":1,"balance":"0x21e19e0b90393da9b38","code":"0x","storage":{}},"0x90f79bf6eb2c4f870365e785982e1f101e93b906":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x976ea74026e726554db657fa54763abd0c3a0aa9":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xa0ee7a142d267c1f36714e4a8f75612f20a79720":{"nonce":0,"balance":"0x21e19e0c9bab2400000","code":"0x","storage":{}},"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266":{"nonce":1,"balance":"0x21e19e0b6a140b55df8","code":"0x","storage":{}}},"best_block_number":"0x2","blocks":[{"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x66cdcc25","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[],"ommers":[]},{"header":{"parentHash":"0x3a52101c98a4319c419681131d3585d70a6cf13a9af25136be20d451eed5480a","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0x6e5f60b37eeaece7dedfc42cc394731a0ae3ed3d3be93c402780b2e23e141175","transactionsRoot":"0x9ceaeb1b16b924afbf4bf4df4c2c49dc9cfbe23ac7a40bf26a704158ea2d352f","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdcc29","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x3b9aca00","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"transaction":{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gas":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","value":"0x0","accessList":[],"input":"0x","r":"0x703a4b4d6dbff2fa2345df73263df2098faa7214863b5ec82c4c07162d87b853","s":"0x17dea762c4ce600ad1d9d2c9ae6dd35b9e526d03c875f868ad0792fd4fad72e0","yParity":"0x0","hash":"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3"}},"impersonated_sender":null}],"ommers":[]},{"header":{"parentHash":"0x0d575f9ca968cd483549172245483a12343afc3cabef80f0fa39855b10b98c70","ommersHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","beneficiary":"0x0000000000000000000000000000000000000000","stateRoot":"0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1","transactionsRoot":"0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988","receiptsRoot":"0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x2","gasLimit":"0x1c9c380","gasUsed":"0x5208","timestamp":"0x66cdcc2b","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x342a1c58","blobGasUsed":"0x0","excessBlobGas":"0x0","extraData":"0x"},"transactions":[{"transaction":{"EIP1559":{"chainId":"0x7a69","nonce":"0x0","gas":"0x5209","maxFeePerGas":"0x77359401","maxPriorityFeePerGas":"0x1","to":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","value":"0x0","accessList":[],"input":"0x","r":"0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0","s":"0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd","yParity":"0x0","hash":"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"}},"impersonated_sender":null}],"ommers":[]}],"transactions":[{"info":{"transaction_hash":"0xf8d5fb22350f52ae8c30cd7f6969eb73de849c8dc010f4215d4c5c24824fe2b3","transaction_index":0,"from":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","to":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","contract_address":null,"traces":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","address":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","maybe_precompile":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x","output":"0x","gas_used":0,"gas_limit":1,"status":"Stop","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}],"exit":"Stop","out":"0x","nonce":0,"gas_used":21000},"receipt":{"type":"0x2","status":"0x1","cumulativeGasUsed":"0x5208","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"block_hash":"0x0d575f9ca968cd483549172245483a12343afc3cabef80f0fa39855b10b98c70","block_number":1},{"info":{"transaction_hash":"0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515","transaction_index":0,"from":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","to":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","contract_address":null,"traces":[{"parent":null,"children":[],"idx":0,"trace":{"depth":0,"success":true,"caller":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","address":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","maybe_precompile":null,"selfdestruct_refund_target":null,"selfdestruct_transferred_value":null,"kind":"CALL","value":"0x0","data":"0x","output":"0x","gas_used":0,"gas_limit":1,"status":"Stop","steps":[],"decoded":{"label":null,"return_data":null,"call_data":null}},"logs":[],"ordering":[]}],"exit":"Stop","out":"0x","nonce":0,"gas_used":21000},"receipt":{"type":"0x2","status":"0x1","cumulativeGasUsed":"0x5208","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"block_hash":"0x1f435a603c1bf6d544a90156b572b96d7a1730028422d800839bae78bb3506d0","block_number":2}]} \ No newline at end of file diff --git a/crates/anvil/tests/it/anvil.rs b/crates/anvil/tests/it/anvil.rs index 50e27c57a..5a952da6b 100644 --- a/crates/anvil/tests/it/anvil.rs +++ b/crates/anvil/tests/it/anvil.rs @@ -1,9 +1,10 @@ //! tests for anvil specific logic +use alloy_consensus::EMPTY_ROOT_HASH; use alloy_eips::BlockNumberOrTag; use alloy_primitives::Address; use alloy_provider::Provider; -use anvil::{spawn, NodeConfig}; +use anvil::{spawn, EthereumHardfork, NodeConfig}; #[tokio::test(flavor = "multi_thread")] async fn test_can_change_mining_mode() { @@ -88,3 +89,29 @@ async fn test_can_handle_large_timestamp() { let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap(); assert_eq!(block.header.timestamp, num); } + +#[tokio::test(flavor = "multi_thread")] +async fn test_shanghai_fields() { + let (api, _handle) = + spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Shanghai.into()))).await; + api.mine_one().await; + + let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap(); + assert_eq!(block.header.withdrawals_root, Some(EMPTY_ROOT_HASH)); + assert_eq!(block.withdrawals, Some(Default::default())); + assert!(block.header.blob_gas_used.is_none()); + assert!(block.header.excess_blob_gas.is_none()); +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_cancun_fields() { + let (api, _handle) = + spawn(NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()))).await; + api.mine_one().await; + + let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap(); + assert_eq!(block.header.withdrawals_root, Some(EMPTY_ROOT_HASH)); + assert_eq!(block.withdrawals, Some(Default::default())); + assert!(block.header.blob_gas_used.is_some()); + assert!(block.header.excess_blob_gas.is_some()); +} diff --git a/crates/anvil/tests/it/anvil_api.rs b/crates/anvil/tests/it/anvil_api.rs index 74728f94b..ce78d72ca 100644 --- a/crates/anvil/tests/it/anvil_api.rs +++ b/crates/anvil/tests/it/anvil_api.rs @@ -7,7 +7,7 @@ use crate::{ }; use alloy_consensus::{SignableTransaction, TxEip1559}; use alloy_network::{EthereumWallet, TransactionBuilder, TxSignerSync}; -use alloy_primitives::{address, fixed_bytes, Address, Bytes, TxKind, U256}; +use alloy_primitives::{address, fixed_bytes, utils::Unit, Address, Bytes, TxKind, U256}; use alloy_provider::{ext::TxPoolApi, Provider}; use alloy_rpc_types::{ anvil::{ @@ -16,9 +16,18 @@ use alloy_rpc_types::{ BlockId, BlockNumberOrTag, TransactionRequest, }; use alloy_serde::WithOtherFields; -use anvil::{eth::api::CLIENT_VERSION, spawn, EthereumHardfork, NodeConfig}; +use anvil::{ + eth::{ + api::CLIENT_VERSION, + backend::mem::{EXECUTOR, P256_DELEGATION_CONTRACT, P256_DELEGATION_RUNTIME_CODE}, + }, + spawn, EthereumHardfork, NodeConfig, +}; use anvil_core::{ - eth::EthRequest, + eth::{ + wallet::{Capabilities, DelegationCapability, WalletCapabilities}, + EthRequest, + }, types::{ReorgOptions, TransactionData}, }; use foundry_evm::revm::primitives::SpecId; @@ -306,7 +315,7 @@ async fn test_set_next_timestamp() { let next = provider.get_block(BlockId::default(), false.into()).await.unwrap().unwrap(); assert_eq!(next.header.number, 2); - assert!(next.header.timestamp > block.header.timestamp); + assert!(next.header.timestamp >= block.header.timestamp); } #[tokio::test(flavor = "multi_thread")] @@ -330,7 +339,7 @@ async fn test_evm_set_time() { api.evm_mine(None).await.unwrap(); let next = provider.get_block(BlockId::default(), false.into()).await.unwrap().unwrap(); - assert!(next.header.timestamp > block.header.timestamp); + assert!(next.header.timestamp >= block.header.timestamp); } #[tokio::test(flavor = "multi_thread")] @@ -599,7 +608,7 @@ async fn test_fork_revert_next_block_timestamp() { api.mine_one().await; let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap(); - assert!(block.header.timestamp > latest_block.header.timestamp); + assert!(block.header.timestamp >= latest_block.header.timestamp); } // test that after a snapshot revert, the env block is reset @@ -793,3 +802,228 @@ async fn test_reorg() { .await; assert!(res.is_err()); } + +// === wallet endpoints === // +#[tokio::test(flavor = "multi_thread")] +async fn can_get_wallet_capabilities() { + let (api, handle) = spawn(NodeConfig::test().with_alphanet(true)).await; + + let provider = handle.http_provider(); + + let init_sponsor_bal = provider.get_balance(EXECUTOR).await.unwrap(); + + let expected_bal = Unit::ETHER.wei().saturating_mul(U256::from(10_000)); + assert_eq!(init_sponsor_bal, expected_bal); + + let p256_code = provider.get_code_at(P256_DELEGATION_CONTRACT).await.unwrap(); + + assert_eq!(p256_code, Bytes::from_static(P256_DELEGATION_RUNTIME_CODE)); + + let capabilities = api.get_capabilities().unwrap(); + + let mut expect_caps = WalletCapabilities::default(); + let cap: Capabilities = Capabilities { + delegation: DelegationCapability { addresses: vec![P256_DELEGATION_CONTRACT] }, + }; + expect_caps.insert(api.chain_id(), cap); + + assert_eq!(capabilities, expect_caps); +} + +#[tokio::test(flavor = "multi_thread")] +async fn can_add_capability() { + let (api, _handle) = spawn(NodeConfig::test().with_alphanet(true)).await; + + let init_capabilities = api.get_capabilities().unwrap(); + + let mut expect_caps = WalletCapabilities::default(); + let cap: Capabilities = Capabilities { + delegation: DelegationCapability { addresses: vec![P256_DELEGATION_CONTRACT] }, + }; + expect_caps.insert(api.chain_id(), cap); + + assert_eq!(init_capabilities, expect_caps); + + let new_cap_addr = Address::with_last_byte(1); + + api.anvil_add_capability(new_cap_addr).unwrap(); + + let capabilities = api.get_capabilities().unwrap(); + + let cap: Capabilities = Capabilities { + delegation: DelegationCapability { + addresses: vec![P256_DELEGATION_CONTRACT, new_cap_addr], + }, + }; + expect_caps.insert(api.chain_id(), cap); + + assert_eq!(capabilities, expect_caps); +} + +#[tokio::test(flavor = "multi_thread")] +async fn can_set_executor() { + let (api, _handle) = spawn(NodeConfig::test().with_alphanet(true)).await; + + let expected_addr = address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); + let pk = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".to_string(); + + let executor = api.anvil_set_executor(pk).unwrap(); + + assert_eq!(executor, expected_addr); +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_arb_get_block() { + let (api, _handle) = spawn(NodeConfig::test().with_chain_id(Some(421611u64))).await; + + // Mine two blocks + api.mine_one().await; + api.mine_one().await; + + let best_number = api.block_number().unwrap().to::(); + + assert_eq!(best_number, 2); + + let block = api.block_by_number(1.into()).await.unwrap().unwrap(); + + assert_eq!(block.header.number, 1); +} + +// Set next_block_timestamp same as previous block +// api.evm_set_next_block_timestamp(0).unwrap(); +#[tokio::test(flavor = "multi_thread")] +async fn test_mine_blk_with_prev_timestamp() { + let (api, handle) = spawn(NodeConfig::test()).await; + let provider = handle.http_provider(); + + let init_blk = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap(); + + let init_number = init_blk.header.number; + let init_timestamp = init_blk.header.timestamp; + + // mock timestamp + api.evm_set_next_block_timestamp(init_timestamp).unwrap(); + + api.mine_one().await; + + let block = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap(); + + let next_blk_num = block.header.number; + let next_blk_timestamp = block.header.timestamp; + + assert_eq!(next_blk_num, init_number + 1); + assert_eq!(next_blk_timestamp, init_timestamp); + + // Sleep for 1 second + tokio::time::sleep(Duration::from_secs(1)).await; + + // Subsequent block should have a greater timestamp than previous block + api.mine_one().await; + + let block = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap(); + + let third_blk_num = block.header.number; + let third_blk_timestmap = block.header.timestamp; + + assert_eq!(third_blk_num, init_number + 2); + assert_ne!(third_blk_timestmap, next_blk_timestamp); + assert!(third_blk_timestmap > next_blk_timestamp); +} + +// increase time by 0 seconds i.e next_block_timestamp = prev_block_timestamp +// api.evm_increase_time(0).unwrap(); +#[tokio::test(flavor = "multi_thread")] +async fn test_increase_time_by_zero() { + let (api, handle) = spawn(NodeConfig::test()).await; + let provider = handle.http_provider(); + + let init_blk = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap(); + + let init_number = init_blk.header.number; + let init_timestamp = init_blk.header.timestamp; + + let _ = api.evm_increase_time(U256::ZERO).await; + + api.mine_one().await; + + let block = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap(); + + let next_blk_num = block.header.number; + let next_blk_timestamp = block.header.timestamp; + + assert_eq!(next_blk_num, init_number + 1); + assert_eq!(next_blk_timestamp, init_timestamp); +} + +// evm_mine(MineOptions::Timestamp(prev_block_timestamp)) +#[tokio::test(flavor = "multi_thread")] +async fn evm_mine_blk_with_same_timestamp() { + let (api, handle) = spawn(NodeConfig::test()).await; + let provider = handle.http_provider(); + + let init_blk = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap(); + + let init_number = init_blk.header.number; + let init_timestamp = init_blk.header.timestamp; + + api.evm_mine(Some(MineOptions::Timestamp(Some(init_timestamp)))).await.unwrap(); + + let block = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap(); + + let next_blk_num = block.header.number; + let next_blk_timestamp = block.header.timestamp; + + assert_eq!(next_blk_num, init_number + 1); + assert_eq!(next_blk_timestamp, init_timestamp); +} + +// mine 4 blocks instantly. +#[tokio::test(flavor = "multi_thread")] +async fn test_mine_blks_with_same_timestamp() { + let (api, handle) = spawn(NodeConfig::test()).await; + let provider = handle.http_provider(); + + let init_blk = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap(); + + let init_number = init_blk.header.number; + let init_timestamp = init_blk.header.timestamp; + + // Mine 4 blocks instantly + let _ = api.anvil_mine(Some(U256::from(4)), None).await; + + let latest_blk_num = api.block_number().unwrap().to::(); + + assert_eq!(latest_blk_num, init_number + 4); + + let mut blk_futs = vec![]; + for i in 1..=4 { + blk_futs.push(provider.get_block(i.into(), false.into())); + } + + let blks = futures::future::join_all(blk_futs) + .await + .into_iter() + .map(|blk| blk.unwrap().unwrap().header.timestamp) + .collect::>(); + + // timestamps should be equal + assert_eq!(blks, vec![init_timestamp; 4]); +} + +// +#[tokio::test(flavor = "multi_thread")] +async fn test_mine_first_block_with_interval() { + let (api, _) = spawn(NodeConfig::test()).await; + + let init_block = api.block_by_number(0.into()).await.unwrap().unwrap(); + let init_timestamp = init_block.header.timestamp; + + // Mine 2 blocks with interval of 60. + let _ = api.anvil_mine(Some(U256::from(2)), Some(U256::from(60))).await; + + let first_block = api.block_by_number(1.into()).await.unwrap().unwrap(); + assert_eq!(first_block.header.timestamp, init_timestamp + 60); + + let second_block = api.block_by_number(2.into()).await.unwrap().unwrap(); + assert_eq!(second_block.header.timestamp, init_timestamp + 120); +} diff --git a/crates/anvil/tests/it/eip7702.rs b/crates/anvil/tests/it/eip7702.rs index 2a0cc0e43..ab787e4eb 100644 --- a/crates/anvil/tests/it/eip7702.rs +++ b/crates/anvil/tests/it/eip7702.rs @@ -1,7 +1,7 @@ use crate::utils::http_provider; use alloy_consensus::{transaction::TxEip7702, SignableTransaction}; use alloy_network::{ReceiptResponse, TransactionBuilder, TxSignerSync}; -use alloy_primitives::{bytes, U256}; +use alloy_primitives::bytes; use alloy_provider::Provider; use alloy_rpc_types::{Authorization, TransactionRequest}; use alloy_serde::WithOtherFields; @@ -44,7 +44,7 @@ async fn can_send_eip7702_tx() { let contract = receipt.contract_address.unwrap(); let authorization = Authorization { - chain_id: U256::from(31337u64), + chain_id: 31337u64, address: contract, nonce: provider.get_transaction_count(from).await.unwrap(), }; diff --git a/crates/anvil/tests/it/fork.rs b/crates/anvil/tests/it/fork.rs index e6db8a063..a35d7c267 100644 --- a/crates/anvil/tests/it/fork.rs +++ b/crates/anvil/tests/it/fork.rs @@ -57,7 +57,6 @@ pub fn fork_config() -> NodeConfig { NodeConfig::test() .with_eth_rpc_url(Some(rpc::next_http_archive_rpc_endpoint())) .with_fork_block_number(Some(BLOCK_NUMBER)) - .silent() } #[tokio::test(flavor = "multi_thread")] @@ -829,10 +828,9 @@ async fn test_fork_init_base_fee() { #[tokio::test(flavor = "multi_thread")] async fn test_reset_fork_on_new_blocks() { - let (api, handle) = spawn( - NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_endpoint())).silent(), - ) - .await; + let (api, handle) = + spawn(NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_endpoint()))) + .await; let anvil_provider = handle.http_provider(); let endpoint = next_http_rpc_endpoint(); @@ -897,7 +895,7 @@ async fn test_fork_block_timestamp() { api.anvil_mine(Some(U256::from(1)), None).await.unwrap(); let latest_block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap(); - assert!(initial_block.header.timestamp < latest_block.header.timestamp); + assert!(initial_block.header.timestamp <= latest_block.header.timestamp); } #[tokio::test(flavor = "multi_thread")] @@ -1216,6 +1214,27 @@ async fn test_arbitrum_fork_dev_balance() { } } +// +#[tokio::test(flavor = "multi_thread")] +async fn test_arb_fork_mining() { + let fork_block_number = 266137031u64; + let fork_rpc = next_rpc_endpoint(NamedChain::Arbitrum); + let (api, _handle) = spawn( + fork_config() + .with_fork_block_number(Some(fork_block_number)) + .with_eth_rpc_url(Some(fork_rpc)), + ) + .await; + + let init_blk_num = api.block_number().unwrap().to::(); + + // Mine one + api.mine_one().await; + let mined_blk_num = api.block_number().unwrap().to::(); + + assert_eq!(mined_blk_num, init_blk_num + 1); +} + // #[tokio::test(flavor = "multi_thread")] async fn test_arbitrum_fork_block_number() { diff --git a/crates/anvil/tests/it/optimism.rs b/crates/anvil/tests/it/optimism.rs index 8de4eab1d..17246f092 100644 --- a/crates/anvil/tests/it/optimism.rs +++ b/crates/anvil/tests/it/optimism.rs @@ -9,7 +9,7 @@ use alloy_rpc_types::TransactionRequest; use alloy_serde::WithOtherFields; use anvil::{spawn, EthereumHardfork, NodeConfig}; use anvil_core::eth::transaction::optimism::DepositTransaction; -use op_alloy_rpc_types::OptimismTransactionFields; +use op_alloy_rpc_types::OpTransactionFields; #[tokio::test(flavor = "multi_thread")] async fn test_deposits_not_supported_if_optimism_disabled() { @@ -26,7 +26,7 @@ async fn test_deposits_not_supported_if_optimism_disabled() { .with_value(U256::from(1234)) .with_gas_limit(21000); - let op_fields = OptimismTransactionFields { + let op_fields = OpTransactionFields { source_hash: Some(b256!( "0000000000000000000000000000000000000000000000000000000000000000" )), @@ -63,7 +63,7 @@ async fn test_send_value_deposit_transaction() { let send_value = U256::from(1234); let before_balance_to = provider.get_balance(to).await.unwrap(); - let op_fields = OptimismTransactionFields { + let op_fields = OpTransactionFields { source_hash: Some(b256!( "0000000000000000000000000000000000000000000000000000000000000000" )), @@ -123,7 +123,7 @@ async fn test_send_value_raw_deposit_transaction() { .with_max_fee_per_gas(20_000_000_000) .with_max_priority_fee_per_gas(1_000_000_000); - let op_fields = OptimismTransactionFields { + let op_fields = OpTransactionFields { source_hash: Some(b256!( "0000000000000000000000000000000000000000000000000000000000000000" )), diff --git a/crates/anvil/tests/it/state.rs b/crates/anvil/tests/it/state.rs index cb8f3b9eb..f7736de2f 100644 --- a/crates/anvil/tests/it/state.rs +++ b/crates/anvil/tests/it/state.rs @@ -1,10 +1,13 @@ //! general eth api tests use crate::abi::Greeter; -use alloy_primitives::{Bytes, Uint, U256}; +use alloy_network::{ReceiptResponse, TransactionBuilder}; +use alloy_primitives::{address, utils::Unit, Bytes, Uint, U256}; use alloy_provider::Provider; -use alloy_rpc_types::BlockId; +use alloy_rpc_types::{BlockId, TransactionRequest}; +use alloy_serde::WithOtherFields; use anvil::{spawn, NodeConfig}; +use foundry_test_utils::rpc::next_http_rpc_endpoint; #[tokio::test(flavor = "multi_thread")] async fn can_load_state() { @@ -155,3 +158,90 @@ async fn can_preserve_historical_states_between_dump_and_load() { assert_eq!(greeting_after_change, "World!"); } + +// +#[tokio::test(flavor = "multi_thread")] +async fn test_fork_load_state() { + let (api, handle) = spawn( + NodeConfig::test() + .with_eth_rpc_url(Some(next_http_rpc_endpoint())) + .with_fork_block_number(Some(21070682u64)), + ) + .await; + + let bob = address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); + let alice = address!("9276449EaC5b4f7Bc17cFC6700f7BeeB86F9bCd0"); + + let provider = handle.http_provider(); + + let init_nonce_bob = provider.get_transaction_count(bob).await.unwrap(); + + let init_balance_alice = provider.get_balance(alice).await.unwrap(); + + let value = Unit::ETHER.wei().saturating_mul(U256::from(1)); // 1 ether + let tx = TransactionRequest::default().with_to(alice).with_value(value).with_from(bob); + let tx = WithOtherFields::new(tx); + + let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap(); + + assert!(receipt.status()); + + let serialized_state = api.serialized_state(false).await.unwrap(); + + let state_dump_block = api.block_number().unwrap(); + + let (api, handle) = spawn( + NodeConfig::test() + .with_eth_rpc_url(Some(next_http_rpc_endpoint())) + .with_fork_block_number(Some(21070686u64)) // Forked chain has moved forward + .with_init_state(Some(serialized_state)), + ) + .await; + + // Ensure the initial block number is the fork_block_number and not the state_dump_block + let block_number = api.block_number().unwrap(); + assert_eq!(block_number, U256::from(21070686u64)); + assert_ne!(block_number, state_dump_block); + + let provider = handle.http_provider(); + + let restart_nonce_bob = provider.get_transaction_count(bob).await.unwrap(); + + let restart_balance_alice = provider.get_balance(alice).await.unwrap(); + + assert_eq!(init_nonce_bob + 1, restart_nonce_bob); + + assert_eq!(init_balance_alice + value, restart_balance_alice); + + // Send another tx to check if the state is preserved + + let tx = TransactionRequest::default().with_to(alice).with_value(value).with_from(bob); + let tx = WithOtherFields::new(tx); + + let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap(); + + assert!(receipt.status()); + + let nonce_bob = provider.get_transaction_count(bob).await.unwrap(); + + let balance_alice = provider.get_balance(alice).await.unwrap(); + + let tx = TransactionRequest::default() + .with_to(alice) + .with_value(value) + .with_from(bob) + .with_nonce(nonce_bob); + let tx = WithOtherFields::new(tx); + + let receipt = provider.send_transaction(tx).await.unwrap().get_receipt().await.unwrap(); + + assert!(receipt.status()); + + let latest_nonce_bob = provider.get_transaction_count(bob).await.unwrap(); + + let latest_balance_alice = provider.get_balance(alice).await.unwrap(); + + assert_eq!(nonce_bob + 1, latest_nonce_bob); + + assert_eq!(balance_alice + value, latest_balance_alice); +} diff --git a/crates/anvil/tests/it/traces.rs b/crates/anvil/tests/it/traces.rs index aaa2ca298..79448ad83 100644 --- a/crates/anvil/tests/it/traces.rs +++ b/crates/anvil/tests/it/traces.rs @@ -5,12 +5,16 @@ use crate::{ }; use alloy_eips::BlockId; use alloy_network::{EthereumWallet, TransactionBuilder}; -use alloy_primitives::{hex, Address, Bytes, U256}; +use alloy_primitives::{ + hex::{self, FromHex}, + Address, Bytes, U256, +}; use alloy_provider::{ ext::{DebugApi, TraceApi}, Provider, }; use alloy_rpc_types::{ + state::StateOverride, trace::{ filter::{TraceFilter, TraceFilterMode}, geth::{ @@ -259,6 +263,50 @@ async fn test_call_tracer_debug_trace_call() { } } +#[tokio::test(flavor = "multi_thread")] +async fn test_debug_trace_call_state_override() { + let (_api, handle) = spawn(NodeConfig::test()).await; + let wallets = handle.dev_wallets().collect::>(); + + let tx = TransactionRequest::default() + .from(wallets[1].address()) + .to("0x1234567890123456789012345678901234567890".parse().unwrap()); + + let override_json = r#"{ + "0x1234567890123456789012345678901234567890": { + "balance": "0x01", + "code": "0x30315f5260205ff3" + } + }"#; + + let state_override: StateOverride = serde_json::from_str(override_json).unwrap(); + + let tx_traces = handle + .http_provider() + .debug_trace_call( + tx.clone(), + BlockId::latest(), + GethDebugTracingCallOptions::default() + .with_tracing_options(GethDebugTracingOptions::default()) + .with_state_overrides(state_override), + ) + .await + .unwrap(); + + match tx_traces { + GethTrace::Default(trace_res) => { + assert_eq!( + trace_res.return_value, + Bytes::from_hex("0000000000000000000000000000000000000000000000000000000000000001") + .unwrap() + ); + } + _ => { + unreachable!() + } + } +} + // #[tokio::test(flavor = "multi_thread")] async fn test_trace_address_fork() { @@ -808,7 +856,7 @@ async fn test_trace_filter() { } let traces = api.trace_filter(tracer).await.unwrap(); - assert_eq!(traces.len(), 9); + assert_eq!(traces.len(), 3); // Test Range Error let latest = provider.get_block_number().await.unwrap(); diff --git a/crates/cast/Cargo.toml b/crates/cast/Cargo.toml index 034a1e148..0b22b4fba 100644 --- a/crates/cast/Cargo.toml +++ b/crates/cast/Cargo.toml @@ -46,9 +46,14 @@ alloy-json-abi.workspace = true alloy-json-rpc.workspace = true alloy-network.workspace = true alloy-primitives.workspace = true -alloy-provider = { workspace = true, features = ["reqwest", "ws", "ipc"] } +alloy-provider = { workspace = true, features = [ + "reqwest", + "ws", + "ipc", + "trace-api", +] } alloy-rlp.workspace = true -alloy-rpc-types = { workspace = true, features = ["eth"] } +alloy-rpc-types = { workspace = true, features = ["eth", "trace"] } alloy-serde.workspace = true alloy-signer-local = { workspace = true, features = ["mnemonic", "keystore"] } alloy-signer.workspace = true diff --git a/crates/cast/bin/args.rs b/crates/cast/bin/args.rs index fdb6a1133..a16436dd2 100644 --- a/crates/cast/bin/args.rs +++ b/crates/cast/bin/args.rs @@ -1,5 +1,6 @@ use crate::cmd::{ - access_list::AccessListArgs, bind::BindArgs, call::CallArgs, create2::Create2Args, + access_list::AccessListArgs, bind::BindArgs, call::CallArgs, + constructor_args::ConstructorArgsArgs, create2::Create2Args, creation_code::CreationCodeArgs, estimate::EstimateArgs, find_block::FindBlockArgs, interface::InterfaceArgs, logs::LogsArgs, mktx::MakeTxArgs, rpc::RpcArgs, run::RunArgs, send::SendTxArgs, storage::StorageArgs, wallet::WalletSubcommands, @@ -8,7 +9,7 @@ use alloy_primitives::{Address, B256, U256}; use alloy_rpc_types::BlockId; use clap::{Parser, Subcommand, ValueHint}; use eyre::Result; -use foundry_cli::opts::{EtherscanOpts, RpcOpts}; +use foundry_cli::opts::{EtherscanOpts, RpcOpts, ShellOpts}; use foundry_common::ens::NameOrAddress; use std::{path::PathBuf, str::FromStr}; @@ -32,6 +33,9 @@ const VERSION_MESSAGE: &str = concat!( pub struct Cast { #[command(subcommand)] pub cmd: CastSubcommand, + + #[clap(flatten)] + pub shell: ShellOpts, } #[derive(Subcommand)] @@ -230,6 +234,38 @@ pub enum CastSubcommand { unit: String, }, + /// Convert a number from decimal to smallest unit with arbitrary decimals. + /// + /// Examples: + /// - 1.0 6 (for USDC, result: 1000000) + /// - 2.5 12 (for 12 decimals token, result: 2500000000000) + /// - 1.23 3 (for 3 decimals token, result: 1230) + #[command(visible_aliases = &["--parse-units", "pun"])] + ParseUnits { + /// The value to convert. + value: Option, + + /// The unit to convert to. + #[arg(default_value = "18")] + unit: u8, + }, + + /// Format a number from smallest unit to decimal with arbitrary decimals. + /// + /// Examples: + /// - 1000000 6 (for USDC, result: 1.0) + /// - 2500000000000 12 (for 12 decimals, result: 2.5) + /// - 1230 3 (for 3 decimals, result: 1.23) + #[command(visible_aliases = &["--format-units", "fun"])] + FormatUnits { + /// The value to format. + value: Option, + + /// The unit to format to. + #[arg(default_value = "18")] + unit: u8, + }, + /// Convert an ETH amount to wei. /// /// Consider using --to-unit. @@ -282,6 +318,10 @@ pub enum CastSubcommand { FromRlp { /// The RLP hex-encoded data. value: Option, + + /// Decode the RLP data as int + #[arg(long, alias = "int")] + as_int: bool, }, /// Converts a number of one base to another @@ -329,10 +369,6 @@ pub enum CastSubcommand { #[arg(long, env = "CAST_FULL_BLOCK")] full: bool, - /// Print the block as JSON. - #[arg(long, short, help_heading = "Display options")] - json: bool, - #[command(flatten)] rpc: RpcOpts, }, @@ -424,10 +460,6 @@ pub enum CastSubcommand { #[arg(long, conflicts_with = "field")] raw: bool, - /// Print as JSON. - #[arg(long, short, help_heading = "Display options")] - json: bool, - #[command(flatten)] rpc: RpcOpts, }, @@ -449,10 +481,6 @@ pub enum CastSubcommand { #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")] cast_async: bool, - /// Print as JSON. - #[arg(long, short, help_heading = "Display options")] - json: bool, - #[command(flatten)] rpc: RpcOpts, }, @@ -483,17 +511,22 @@ pub enum CastSubcommand { /// /// Similar to `abi-decode --input`, but function selector MUST be prefixed in `calldata` /// string - #[command(visible_aliases = &["--calldata-decode","cdd"])] + #[command(visible_aliases = &["--calldata-decode", "cdd"])] CalldataDecode { /// The function signature in the format `()()`. sig: String, /// The ABI-encoded calldata. calldata: String, + }, - /// Print the decoded calldata as JSON. - #[arg(long, short, help_heading = "Display options")] - json: bool, + /// Decode ABI-encoded string. + /// + /// Similar to `calldata-decode --input`, but the function argument is a `string` + #[command(visible_aliases = &["--string-decode", "sd"])] + StringDecode { + /// The ABI-encoded string. + data: String, }, /// Decode ABI-encoded input or output data. @@ -512,10 +545,6 @@ pub enum CastSubcommand { /// Whether to decode the input or output data. #[arg(long, short, help_heading = "Decode input data instead of output data")] input: bool, - - /// Print the decoded calldata as JSON. - #[arg(long, short, help_heading = "Display options")] - json: bool, }, /// ABI encode the given function argument, excluding the selector. @@ -602,10 +631,6 @@ pub enum CastSubcommand { FourByteDecode { /// The ABI-encoded calldata. calldata: Option, - - /// Print the decoded calldata as JSON. - #[arg(long, short, help_heading = "Display options")] - json: bool, }, /// Get the event signature for a given topic 0 from https://openchain.xyz. @@ -898,6 +923,14 @@ pub enum CastSubcommand { command: WalletSubcommands, }, + /// Download a contract creation code from Etherscan and RPC. + #[command(visible_alias = "cc")] + CreationCode(CreationCodeArgs), + + /// Display constructor arguments used for the contract initialization. + #[command(visible_alias = "cra")] + ConstructorArgs(ConstructorArgsArgs), + /// Generate a Solidity interface from a given ABI. /// /// Currently does not support ABI encoder v2. diff --git a/crates/cast/bin/cmd/access_list.rs b/crates/cast/bin/cmd/access_list.rs index 553d9c9ad..c283f60c4 100644 --- a/crates/cast/bin/cmd/access_list.rs +++ b/crates/cast/bin/cmd/access_list.rs @@ -35,10 +35,6 @@ pub struct AccessListArgs { #[arg(long, short = 'B')] block: Option, - /// Print the access list as JSON. - #[arg(long, short, help_heading = "Display options")] - json: bool, - #[command(flatten)] tx: TransactionOpts, @@ -48,7 +44,7 @@ pub struct AccessListArgs { impl AccessListArgs { pub async fn run(self) -> Result<()> { - let Self { to, sig, args, tx, eth, block, json: to_json } = self; + let Self { to, sig, args, tx, eth, block } = self; let config = Config::from(ð); let provider = utils::get_provider(&config)?; @@ -65,9 +61,9 @@ impl AccessListArgs { let cast = Cast::new(&provider); - let access_list: String = cast.access_list(&tx, block, to_json).await?; + let access_list: String = cast.access_list(&tx, block).await?; - println!("{access_list}"); + sh_println!("{access_list}")?; Ok(()) } diff --git a/crates/cast/bin/cmd/call.rs b/crates/cast/bin/cmd/call.rs index fe0a244df..aefc5f1c0 100644 --- a/crates/cast/bin/cmd/call.rs +++ b/crates/cast/bin/cmd/call.rs @@ -69,10 +69,6 @@ pub struct CallArgs { #[arg(long, short)] block: Option, - /// Print the decoded output as JSON. - #[arg(long, short, help_heading = "Display options")] - json: bool, - /// Enable Alphanet features. #[arg(long, alias = "odyssey")] pub alphanet: bool, @@ -131,7 +127,6 @@ impl CallArgs { decode_internal, labels, data, - json, .. } = self; @@ -205,7 +200,7 @@ impl CallArgs { return Ok(()); } - println!("{}", Cast::new(provider).call(&tx, func.as_ref(), block, json).await?); + sh_println!("{}", Cast::new(provider).call(&tx, func.as_ref(), block).await?)?; Ok(()) } diff --git a/crates/cast/bin/cmd/constructor_args.rs b/crates/cast/bin/cmd/constructor_args.rs new file mode 100644 index 000000000..b0a08704f --- /dev/null +++ b/crates/cast/bin/cmd/constructor_args.rs @@ -0,0 +1,100 @@ +use alloy_dyn_abi::DynSolType; +use alloy_primitives::{Address, Bytes}; +use clap::{command, Parser}; +use eyre::{eyre, OptionExt, Result}; +use foundry_block_explorers::Client; +use foundry_cli::{ + opts::{EtherscanOpts, RpcOpts}, + utils, +}; +use foundry_config::Config; + +use super::{ + creation_code::fetch_creation_code, + interface::{fetch_abi_from_etherscan, load_abi_from_file}, +}; + +/// CLI arguments for `cast creation-args`. +#[derive(Parser)] +pub struct ConstructorArgsArgs { + /// An Ethereum address, for which the bytecode will be fetched. + contract: Address, + + /// Path to file containing the contract's JSON ABI. It's necessary if the target contract is + /// not verified on Etherscan + #[arg(long)] + abi_path: Option, + + #[command(flatten)] + etherscan: EtherscanOpts, + + #[command(flatten)] + rpc: RpcOpts, +} + +impl ConstructorArgsArgs { + pub async fn run(self) -> Result<()> { + let Self { contract, etherscan, rpc, abi_path } = self; + + let config = Config::from(ðerscan); + let chain = config.chain.unwrap_or_default(); + let api_key = config.get_etherscan_api_key(Some(chain)).unwrap_or_default(); + let client = Client::new(chain, api_key)?; + + let config = Config::from(&rpc); + let provider = utils::get_provider(&config)?; + + let bytecode = fetch_creation_code(contract, client, provider).await?; + + let args_arr = parse_constructor_args(bytecode, contract, ðerscan, abi_path).await?; + for arg in args_arr { + let _ = sh_println!("{arg}"); + } + + Ok(()) + } +} + +/// Fetches the constructor arguments values and types from the creation bytecode and ABI. +async fn parse_constructor_args( + bytecode: Bytes, + contract: Address, + etherscan: &EtherscanOpts, + abi_path: Option, +) -> Result> { + let abi = if let Some(abi_path) = abi_path { + load_abi_from_file(&abi_path, None)? + } else { + fetch_abi_from_etherscan(contract, etherscan).await? + }; + + let abi = abi.into_iter().next().ok_or_eyre("No ABI found.")?; + let (abi, _) = abi; + + let constructor = abi.constructor.ok_or_else(|| eyre!("No constructor found."))?; + + if constructor.inputs.is_empty() { + return Err(eyre!("No constructor arguments found.")); + } + + let args_size = constructor.inputs.len() * 32; + let args_bytes = Bytes::from(bytecode[bytecode.len() - args_size..].to_vec()); + + let display_args: Vec = args_bytes + .chunks(32) + .enumerate() + .map(|(i, arg)| { + format_arg(&constructor.inputs[i].ty, arg).expect("Failed to format argument.") + }) + .collect(); + + Ok(display_args) +} + +fn format_arg(ty: &str, arg: &[u8]) -> Result { + let arg_type: DynSolType = ty.parse().expect("Invalid ABI type."); + let decoded = arg_type.abi_decode(arg)?; + let bytes = Bytes::from(arg.to_vec()); + + Ok(format!("{bytes} → {decoded:?}")) +} diff --git a/crates/cast/bin/cmd/create2.rs b/crates/cast/bin/cmd/create2.rs index ebf2b3eca..17523e094 100644 --- a/crates/cast/bin/cmd/create2.rs +++ b/crates/cast/bin/cmd/create2.rs @@ -124,7 +124,7 @@ impl Create2Args { if let Some(salt) = salt { let salt = hex::FromHex::from_hex(salt)?; let address = deployer.create2(salt, init_code_hash); - println!("{address}"); + sh_println!("{address}")?; return Ok(Create2Output { address, salt }); } @@ -191,11 +191,12 @@ impl Create2Args { rng.fill_bytes(remaining); } - println!("Configuration:"); - println!("Init code hash: {init_code_hash}"); - println!("Regex patterns: {:?}", regex.patterns()); - println!(); - println!("Starting to generate deterministic contract address with {n_threads} threads..."); + sh_println!("Configuration:")?; + sh_println!("Init code hash: {init_code_hash}")?; + sh_println!("Regex patterns: {:?}\n", regex.patterns())?; + sh_println!( + "Starting to generate deterministic contract address with {n_threads} threads..." + )?; let mut handles = Vec::with_capacity(n_threads); let found = Arc::new(AtomicBool::new(false)); let timer = Instant::now(); @@ -249,9 +250,9 @@ impl Create2Args { let results = handles.into_iter().filter_map(|h| h.join().unwrap()).collect::>(); let (address, salt) = results.into_iter().next().unwrap(); - println!("Successfully found contract address in {:?}", timer.elapsed()); - println!("Address: {address}"); - println!("Salt: {salt} ({})", U256::from_be_bytes(salt.0)); + sh_println!("Successfully found contract address in {:?}", timer.elapsed())?; + sh_println!("Address: {address}")?; + sh_println!("Salt: {salt} ({})", U256::from_be_bytes(salt.0))?; Ok(Create2Output { address, salt }) } diff --git a/crates/cast/bin/cmd/creation_code.rs b/crates/cast/bin/cmd/creation_code.rs new file mode 100644 index 000000000..bcafeac94 --- /dev/null +++ b/crates/cast/bin/cmd/creation_code.rs @@ -0,0 +1,167 @@ +use alloy_primitives::{Address, Bytes}; +use alloy_provider::{ext::TraceApi, Provider}; +use alloy_rpc_types::trace::parity::{Action, CreateAction, CreateOutput, TraceOutput}; +use cast::SimpleCast; +use clap::{command, Parser}; +use eyre::{eyre, OptionExt, Result}; +use foundry_block_explorers::Client; +use foundry_cli::{ + opts::{EtherscanOpts, RpcOpts}, + utils, +}; +use foundry_common::provider::RetryProvider; +use foundry_config::Config; + +use super::interface::{fetch_abi_from_etherscan, load_abi_from_file}; + +/// CLI arguments for `cast creation-code`. +#[derive(Parser)] +pub struct CreationCodeArgs { + /// An Ethereum address, for which the bytecode will be fetched. + contract: Address, + + /// Path to file containing the contract's JSON ABI. It's necessary if the target contract is + /// not verified on Etherscan. + #[arg(long)] + abi_path: Option, + + /// Disassemble bytecodes into individual opcodes. + #[arg(long)] + disassemble: bool, + + /// Return creation bytecode without constructor arguments appended. + #[arg(long, conflicts_with = "only_args")] + without_args: bool, + + /// Return only constructor arguments. + #[arg(long)] + only_args: bool, + + #[command(flatten)] + etherscan: EtherscanOpts, + + #[command(flatten)] + rpc: RpcOpts, +} + +impl CreationCodeArgs { + pub async fn run(self) -> Result<()> { + let Self { contract, etherscan, rpc, disassemble, without_args, only_args, abi_path } = + self; + + let config = Config::from(ðerscan); + let chain = config.chain.unwrap_or_default(); + let api_key = config.get_etherscan_api_key(Some(chain)).unwrap_or_default(); + let client = Client::new(chain, api_key)?; + + let config = Config::from(&rpc); + let provider = utils::get_provider(&config)?; + + let bytecode = fetch_creation_code(contract, client, provider).await?; + + let bytecode = + parse_code_output(bytecode, contract, ðerscan, abi_path, without_args, only_args) + .await?; + + if disassemble { + let _ = sh_println!("{}", SimpleCast::disassemble(&bytecode)?); + } else { + let _ = sh_println!("{bytecode}"); + } + + Ok(()) + } +} + +/// Parses the creation bytecode and returns one of the following: +/// - The complete bytecode +/// - The bytecode without constructor arguments +/// - Only the constructor arguments +async fn parse_code_output( + bytecode: Bytes, + contract: Address, + etherscan: &EtherscanOpts, + abi_path: Option, + without_args: bool, + only_args: bool, +) -> Result { + if !without_args && !only_args { + return Ok(bytecode); + } + + let abi = if let Some(abi_path) = abi_path { + load_abi_from_file(&abi_path, None)? + } else { + fetch_abi_from_etherscan(contract, etherscan).await? + }; + + let abi = abi.into_iter().next().ok_or_eyre("No ABI found.")?; + let (abi, _) = abi; + + if abi.constructor.is_none() { + if only_args { + return Err(eyre!("No constructor found.")); + } + return Ok(bytecode); + } + + let constructor = abi.constructor.unwrap(); + if constructor.inputs.is_empty() { + if only_args { + return Err(eyre!("No constructor arguments found.")); + } + return Ok(bytecode); + } + + let args_size = constructor.inputs.len() * 32; + + let bytecode = if without_args { + Bytes::from(bytecode[..bytecode.len() - args_size].to_vec()) + } else if only_args { + Bytes::from(bytecode[bytecode.len() - args_size..].to_vec()) + } else { + unreachable!(); + }; + + Ok(bytecode) +} + +/// Fetches the creation code of a contract from Etherscan and RPC. +pub async fn fetch_creation_code( + contract: Address, + client: Client, + provider: RetryProvider, +) -> Result { + let creation_data = client.contract_creation_data(contract).await?; + let creation_tx_hash = creation_data.transaction_hash; + let tx_data = provider.get_transaction_by_hash(creation_tx_hash).await?; + let tx_data = tx_data.ok_or_eyre("Could not find creation tx data.")?; + + let bytecode = if tx_data.inner.to.is_none() { + // Contract was created using a standard transaction + tx_data.inner.input + } else { + // Contract was created using a factory pattern or create2 + // Extract creation code from tx traces + let mut creation_bytecode = None; + + let traces = provider.trace_transaction(creation_tx_hash).await.map_err(|e| { + eyre!("Could not fetch traces for transaction {}: {}", creation_tx_hash, e) + })?; + + for trace in traces { + if let Some(TraceOutput::Create(CreateOutput { address, .. })) = trace.trace.result { + if address == contract { + creation_bytecode = match trace.trace.action { + Action::Create(CreateAction { init, .. }) => Some(init), + _ => None, + }; + } + } + } + + creation_bytecode.ok_or_else(|| eyre!("Could not find contract creation trace."))? + }; + + Ok(bytecode) +} diff --git a/crates/cast/bin/cmd/estimate.rs b/crates/cast/bin/cmd/estimate.rs index 315ba91dc..3454db197 100644 --- a/crates/cast/bin/cmd/estimate.rs +++ b/crates/cast/bin/cmd/estimate.rs @@ -100,7 +100,7 @@ impl EstimateArgs { .await?; let gas = provider.estimate_gas(&tx).block(block.unwrap_or_default()).await?; - println!("{gas}"); + sh_println!("{gas}")?; Ok(()) } } diff --git a/crates/cast/bin/cmd/find_block.rs b/crates/cast/bin/cmd/find_block.rs index e598a2121..dc7750490 100644 --- a/crates/cast/bin/cmd/find_block.rs +++ b/crates/cast/bin/cmd/find_block.rs @@ -77,7 +77,7 @@ impl FindBlockArgs { } matching_block.unwrap_or(low_block) }; - println!("{block_num}"); + sh_println!("{block_num}")?; Ok(()) } diff --git a/crates/cast/bin/cmd/interface.rs b/crates/cast/bin/cmd/interface.rs index b8de8d84d..659ce6cca 100644 --- a/crates/cast/bin/cmd/interface.rs +++ b/crates/cast/bin/cmd/interface.rs @@ -4,7 +4,7 @@ use clap::Parser; use eyre::{Context, Result}; use foundry_block_explorers::Client; use foundry_cli::opts::EtherscanOpts; -use foundry_common::{compile::ProjectCompiler, fs}; +use foundry_common::{compile::ProjectCompiler, fs, shell}; use foundry_compilers::{info::ContractInfo, utils::canonicalize}; use foundry_config::{load_config_with_root, try_find_project_root, Config}; use itertools::Itertools; @@ -44,17 +44,13 @@ pub struct InterfaceArgs { )] output: Option, - /// If specified, the interface will be output as JSON rather than Solidity. - #[arg(long, short)] - json: bool, - #[command(flatten)] etherscan: EtherscanOpts, } impl InterfaceArgs { pub async fn run(self) -> Result<()> { - let Self { contract, name, pragma, output: output_location, etherscan, json } = self; + let Self { contract, name, pragma, output: output_location, etherscan } = self; // Determine if the target contract is an ABI file, a local contract or an Ethereum address. let abis = if Path::new(&contract).is_file() && @@ -75,7 +71,7 @@ impl InterfaceArgs { let interfaces = get_interfaces(abis)?; // Print result or write to file. - let res = if json { + let res = if shell::is_json() { // Format as JSON. interfaces.iter().map(|iface| &iface.json_abi).format("\n").to_string() } else { @@ -93,9 +89,9 @@ impl InterfaceArgs { fs::create_dir_all(parent)?; } fs::write(&loc, res)?; - println!("Saved interface at {}", loc.display()); + sh_println!("Saved interface at {}", loc.display())?; } else { - print!("{res}"); + sh_print!("{res}")?; } Ok(()) @@ -108,7 +104,7 @@ struct InterfaceSource { } /// Load the ABI from a file. -fn load_abi_from_file(path: &str, name: Option) -> Result> { +pub fn load_abi_from_file(path: &str, name: Option) -> Result> { let file = std::fs::read_to_string(path).wrap_err("unable to read abi file")?; let obj: ContractObject = serde_json::from_str(&file)?; let abi = obj.abi.ok_or_else(|| eyre::eyre!("could not find ABI in file {path}"))?; @@ -139,7 +135,7 @@ fn load_abi_from_artifact(path_or_contract: &str) -> Result Result> { diff --git a/crates/cast/bin/cmd/logs.rs b/crates/cast/bin/cmd/logs.rs index 51b95cffc..154b5c9d2 100644 --- a/crates/cast/bin/cmd/logs.rs +++ b/crates/cast/bin/cmd/logs.rs @@ -49,26 +49,14 @@ pub struct LogsArgs { #[arg(long)] subscribe: bool, - /// Print the logs as JSON.s - #[arg(long, short, help_heading = "Display options")] - json: bool, - #[command(flatten)] eth: EthereumOpts, } impl LogsArgs { pub async fn run(self) -> Result<()> { - let Self { - from_block, - to_block, - address, - sig_or_topic, - topics_or_args, - subscribe, - json, - eth, - } = self; + let Self { from_block, to_block, address, sig_or_topic, topics_or_args, subscribe, eth } = + self; let config = Config::from(ð); let provider = utils::get_provider(&config)?; @@ -88,10 +76,8 @@ impl LogsArgs { let filter = build_filter(from_block, to_block, address, sig_or_topic, topics_or_args)?; if !subscribe { - let logs = cast.filter_logs(filter, json).await?; - - println!("{logs}"); - + let logs = cast.filter_logs(filter).await?; + sh_println!("{logs}")?; return Ok(()) } @@ -104,7 +90,7 @@ impl LogsArgs { .await?; let cast = Cast::new(&provider); let mut stdout = io::stdout(); - cast.subscribe(filter, &mut stdout, json).await?; + cast.subscribe(filter, &mut stdout).await?; Ok(()) } diff --git a/crates/cast/bin/cmd/mktx.rs b/crates/cast/bin/cmd/mktx.rs index 8a45b7363..7837aaed0 100644 --- a/crates/cast/bin/cmd/mktx.rs +++ b/crates/cast/bin/cmd/mktx.rs @@ -105,7 +105,7 @@ impl MakeTxArgs { let tx = tx.build(&EthereumWallet::new(signer)).await?; let signed_tx = hex::encode(tx.encoded_2718()); - println!("0x{signed_tx}"); + sh_println!("0x{signed_tx}")?; Ok(()) } diff --git a/crates/cast/bin/cmd/mod.rs b/crates/cast/bin/cmd/mod.rs index 6c9044174..49e3ed2ef 100644 --- a/crates/cast/bin/cmd/mod.rs +++ b/crates/cast/bin/cmd/mod.rs @@ -8,7 +8,9 @@ pub mod access_list; pub mod bind; pub mod call; +pub mod constructor_args; pub mod create2; +pub mod creation_code; pub mod estimate; pub mod find_block; pub mod interface; diff --git a/crates/cast/bin/cmd/rpc.rs b/crates/cast/bin/cmd/rpc.rs index cae5d3386..d901c760b 100644 --- a/crates/cast/bin/cmd/rpc.rs +++ b/crates/cast/bin/cmd/rpc.rs @@ -53,7 +53,7 @@ impl RpcArgs { } else { serde_json::Value::Array(params.into_iter().map(value_or_string).collect()) }; - println!("{}", Cast::new(provider).rpc(&method, params).await?); + sh_println!("{}", Cast::new(provider).rpc(&method, params).await?)?; Ok(()) } } diff --git a/crates/cast/bin/cmd/run.rs b/crates/cast/bin/cmd/run.rs index 9d04ed1e2..11c7b507e 100644 --- a/crates/cast/bin/cmd/run.rs +++ b/crates/cast/bin/cmd/run.rs @@ -1,7 +1,7 @@ use alloy_primitives::U256; use alloy_provider::Provider; use alloy_rpc_types::BlockTransactions; -use cast::{revm::primitives::EnvWithHandlerCfg, traces::TraceKind}; +use cast::revm::primitives::EnvWithHandlerCfg; use clap::Parser; use eyre::{Result, WrapErr}; use foundry_cli::{ @@ -45,7 +45,7 @@ pub struct RunArgs { /// Executes the transaction only with the state from the previous block. /// /// May result in different results than the live execution! - #[arg(long, short)] + #[arg(long)] quick: bool, /// Prints the full address of the contract. @@ -170,7 +170,7 @@ impl RunArgs { // Set the state to the moment right before the transaction if !self.quick { - println!("Executing previous transactions from the block."); + sh_println!("Executing previous transactions from the block.")?; if let Some(block) = block { let pb = init_progress(block.transactions.len() as u64, "tx"); @@ -235,7 +235,7 @@ impl RunArgs { if let Some(to) = tx.to { trace!(tx=?tx.hash, to=?to, "executing call transaction"); - TraceResult::from_raw(executor.transact_with_env(env)?, TraceKind::Execution) + TraceResult::try_from(executor.transact_with_env(env))? } else { trace!(tx=?tx.hash, "executing create transaction"); TraceResult::try_from(executor.deploy_with_env(env, None))? diff --git a/crates/cast/bin/cmd/send.rs b/crates/cast/bin/cmd/send.rs index 1616a25d7..c05ce513d 100644 --- a/crates/cast/bin/cmd/send.rs +++ b/crates/cast/bin/cmd/send.rs @@ -13,7 +13,7 @@ use foundry_cli::{ opts::{EthereumOpts, TransactionOpts}, utils, }; -use foundry_common::{cli_warn, ens::NameOrAddress}; +use foundry_common::ens::NameOrAddress; use foundry_config::Config; use foundry_wallets::WalletSigner; use foundry_zksync_core::{self, convert::ConvertAddress}; @@ -59,10 +59,6 @@ pub struct SendTxArgs { #[arg(long, default_value = "1")] confirmations: u64, - /// Print the transaction receipt as JSON. - #[arg(long, short, help_heading = "Display options")] - json: bool, - #[command(subcommand)] command: Option, @@ -121,7 +117,6 @@ impl SendTxArgs { mut args, tx, confirmations, - json: to_json, command, unlocked, path, @@ -172,7 +167,7 @@ impl SendTxArgs { // switch chain if current chain id is not the same as the one specified in the // config if config_chain_id != current_chain_id { - cli_warn!("Switching to chain {}", config_chain); + sh_warn!("Switching to chain {}", config_chain)?; provider .raw_request( "wallet_switchEthereumChain".into(), @@ -186,7 +181,7 @@ impl SendTxArgs { let (tx, _) = builder.build(config.sender).await?; - cast_send(provider, tx, cast_async, confirmations, timeout, to_json).await + cast_send(provider, tx, cast_async, confirmations, timeout).await // Case 2: // An option to use a local signer was provided. // If we cannot successfully instantiate a local signer, then we will assume we don't have @@ -207,7 +202,6 @@ impl SendTxArgs { cast_async, confirmations, timeout, - to_json, signer, ) .await @@ -220,7 +214,7 @@ impl SendTxArgs { .wallet(wallet) .on_provider(&provider); - cast_send(provider, tx, cast_async, confirmations, timeout, to_json).await + cast_send(provider, tx, cast_async, confirmations, timeout).await } } } @@ -232,14 +226,13 @@ async fn cast_send, T: Transport + Clone>( cast_async: bool, confs: u64, timeout: u64, - to_json: bool, ) -> Result<()> { let cast = Cast::new(provider); let pending_tx = cast.send(tx).await?; let tx_hash = pending_tx.inner().tx_hash(); - handle_transaction_result(&cast, tx_hash, cast_async, confs, timeout, to_json).await + handle_transaction_result(&cast, tx_hash, cast_async, confs, timeout).await } #[allow(clippy::too_many_arguments)] @@ -250,7 +243,6 @@ async fn cast_send_zk, T: Transport + Clone>( cast_async: bool, confs: u64, timeout: u64, - to_json: bool, signer: WalletSigner, ) -> Result<()> { // ZkSync transaction @@ -276,7 +268,7 @@ async fn cast_send_zk, T: Transport + Clone>( // Use send_raw_transaction for ZKSync let tx_hash = provider.send_raw_transaction(&tx).await?.tx_hash().to_owned(); let cast = Cast::new(provider); - handle_transaction_result(&cast, &tx_hash, cast_async, confs, timeout, to_json).await + handle_transaction_result(&cast, &tx_hash, cast_async, confs, timeout).await } async fn handle_transaction_result, T: Transport + Clone>( @@ -285,15 +277,13 @@ async fn handle_transaction_result, T: Transport + Cl cast_async: bool, confs: u64, timeout: u64, - to_json: bool, ) -> Result<()> { if cast_async { - println!("{tx_hash:#x}"); + sh_println!("{tx_hash:#x}")?; } else { - let receipt = cast - .receipt(format!("{tx_hash:#x}"), None, confs, Some(timeout), false, to_json) - .await?; - println!("{receipt}"); + let receipt = + cast.receipt(format!("{tx_hash:#x}"), None, confs, Some(timeout), false).await?; + sh_println!("{receipt}")?; } Ok(()) diff --git a/crates/cast/bin/cmd/storage.rs b/crates/cast/bin/cmd/storage.rs index a8ced3639..9fca4172e 100644 --- a/crates/cast/bin/cmd/storage.rs +++ b/crates/cast/bin/cmd/storage.rs @@ -92,7 +92,7 @@ impl StorageArgs { // Slot was provided, perform a simple RPC call if let Some(slot) = slot { let cast = Cast::new(provider); - println!("{}", cast.storage(address, slot, block).await?); + sh_println!("{}", cast.storage(address, slot, block).await?)?; return Ok(()); } @@ -120,7 +120,7 @@ impl StorageArgs { // Not a forge project or artifact not found // Get code from Etherscan - eprintln!("No matching artifacts found, fetching source code from Etherscan..."); + sh_warn!("No matching artifacts found, fetching source code from Etherscan...")?; if !self.etherscan.has_key() { eyre::bail!("You must provide an Etherscan API key if you're fetching a remote contract's storage."); @@ -161,7 +161,7 @@ impl StorageArgs { if is_storage_layout_empty(&artifact.storage_layout) && auto_detect { // try recompiling with the minimum version - eprintln!("The requested contract was compiled with {version} while the minimum version for storage layouts is {MIN_SOLC} and as a result the output may be empty."); + sh_warn!("The requested contract was compiled with {version} while the minimum version for storage layouts is {MIN_SOLC} and as a result the output may be empty.")?; let solc = Solc::find_or_install(&MIN_SOLC)?; project.compiler = SolcCompiler::Specific(solc); if let Ok(output) = ProjectCompiler::new().quiet(true).compile(&project) { @@ -223,7 +223,7 @@ async fn fetch_and_print_storage, T: Transport + Clon pretty: bool, ) -> Result<()> { if is_storage_layout_empty(&artifact.storage_layout) { - eprintln!("Storage layout is empty."); + sh_warn!("Storage layout is empty.")?; Ok(()) } else { let layout = artifact.storage_layout.as_ref().unwrap().clone(); @@ -255,7 +255,7 @@ async fn fetch_storage_slots, T: Transport + Clone>( fn print_storage(layout: StorageLayout, values: Vec, pretty: bool) -> Result<()> { if !pretty { - println!("{}", serde_json::to_string_pretty(&serde_json::to_value(layout)?)?); + sh_println!("{}", serde_json::to_string_pretty(&serde_json::to_value(layout)?)?)?; return Ok(()) } @@ -281,7 +281,7 @@ fn print_storage(layout: StorageLayout, values: Vec, pretty: bool) ]); } - println!("{table}"); + sh_println!("{table}")?; Ok(()) } diff --git a/crates/cast/bin/cmd/wallet/list.rs b/crates/cast/bin/cmd/wallet/list.rs index 88b948605..be29cb22b 100644 --- a/crates/cast/bin/cmd/wallet/list.rs +++ b/crates/cast/bin/cmd/wallet/list.rs @@ -1,7 +1,7 @@ use clap::Parser; use eyre::Result; -use foundry_common::fs; +use foundry_common::{fs, sh_err, sh_println}; use foundry_config::Config; use foundry_wallets::multi_wallet::MultiWalletOptsBuilder; @@ -61,12 +61,14 @@ impl ListArgs { .available_senders(self.max_senders.unwrap()) .await? .iter() - .for_each(|sender| println!("{} ({})", sender, $label)); + .for_each(|sender| { + let _ = sh_println!("{} ({})", sender, $label); + }) } } Err(e) => { if !self.all { - println!("{}", e) + sh_err!("{}", e)?; } } } @@ -97,7 +99,7 @@ impl ListArgs { if path.is_file() { if let Some(file_name) = path.file_name() { if let Some(name) = file_name.to_str() { - println!("{name} (Local)"); + sh_println!("{name} (Local)")?; } } } diff --git a/crates/cast/bin/cmd/wallet/mod.rs b/crates/cast/bin/cmd/wallet/mod.rs index 893a0f0ec..8023b8bdf 100644 --- a/crates/cast/bin/cmd/wallet/mod.rs +++ b/crates/cast/bin/cmd/wallet/mod.rs @@ -7,11 +7,11 @@ use alloy_signer_local::{ coins_bip39::{English, Entropy, Mnemonic}, MnemonicBuilder, PrivateKeySigner, }; -use cast::revm::primitives::{Authorization, U256}; +use cast::revm::primitives::Authorization; use clap::Parser; use eyre::{Context, Result}; use foundry_cli::{opts::RpcOpts, utils}; -use foundry_common::fs; +use foundry_common::{fs, sh_println, shell}; use foundry_config::Config; use foundry_wallets::{RawWalletOpts, WalletOpts, WalletSigner}; use rand::thread_rng; @@ -49,10 +49,6 @@ pub enum WalletSubcommands { /// Number of wallets to generate. #[arg(long, short, default_value = "1")] number: u32, - - /// Output generated wallets as JSON. - #[arg(long, short, default_value = "false")] - json: bool, }, /// Generates a random BIP39 mnemonic phrase @@ -215,10 +211,10 @@ pub enum WalletSubcommands { impl WalletSubcommands { pub async fn run(self) -> Result<()> { match self { - Self::New { path, unsafe_password, number, json, .. } => { + Self::New { path, unsafe_password, number, .. } => { let mut rng = thread_rng(); - let mut json_values = if json { Some(vec![]) } else { None }; + let mut json_values = if shell::is_json() { Some(vec![]) } else { None }; if let Some(path) = path { let path = match dunce::canonicalize(path.clone()) { Ok(path) => path, @@ -255,16 +251,16 @@ impl WalletSubcommands { } )); } else { - println!( + sh_println!( "Created new encrypted keystore file: {}", path.join(uuid).display() - ); - println!("Address: {}", wallet.address().to_checksum(None)); + )?; + sh_println!("Address: {}", wallet.address().to_checksum(None))?; } } if let Some(json) = json_values.as_ref() { - println!("{}", serde_json::to_string_pretty(json)?); + sh_println!("{}", serde_json::to_string_pretty(json)?)?; } } else { for _ in 0..number { @@ -276,30 +272,35 @@ impl WalletSubcommands { "private_key": format!("0x{}", hex::encode(wallet.credential().to_bytes())), })) } else { - println!("Successfully created new keypair."); - println!("Address: {}", wallet.address().to_checksum(None)); - println!( + sh_println!("Successfully created new keypair.")?; + sh_println!("Address: {}", wallet.address().to_checksum(None))?; + sh_println!( "Private key: 0x{}", hex::encode(wallet.credential().to_bytes()) - ); + )?; } } if let Some(json) = json_values.as_ref() { - println!("{}", serde_json::to_string_pretty(json)?); + sh_println!("{}", serde_json::to_string_pretty(json)?)?; } } } Self::NewMnemonic { words, accounts, entropy } => { let phrase = if let Some(entropy) = entropy { let entropy = Entropy::from_slice(hex::decode(entropy)?)?; - println!("{}", "Generating mnemonic from provided entropy...".yellow()); Mnemonic::::new_from_entropy(entropy).to_phrase() } else { let mut rng = thread_rng(); Mnemonic::::new_with_count(&mut rng, words)?.to_phrase() }; + let format_json = shell::is_json(); + + if !format_json { + sh_println!("{}", "Generating mnemonic from provided entropy...".yellow())?; + } + let builder = MnemonicBuilder::::default().phrase(phrase.as_str()); let derivation_path = "m/44'/60'/0'/0/"; let wallets = (0..accounts) @@ -308,13 +309,33 @@ impl WalletSubcommands { let wallets = wallets.into_iter().map(|b| b.build()).collect::, _>>()?; - println!("{}", "Successfully generated a new mnemonic.".green()); - println!("Phrase:\n{phrase}"); - println!("\nAccounts:"); + if !format_json { + sh_println!("{}", "Successfully generated a new mnemonic.".green())?; + sh_println!("Phrase:\n{phrase}")?; + sh_println!("\nAccounts:")?; + } + + let mut accounts = json!([]); for (i, wallet) in wallets.iter().enumerate() { - println!("- Account {i}:"); - println!("Address: {}", wallet.address()); - println!("Private key: 0x{}\n", hex::encode(wallet.credential().to_bytes())); + let private_key = hex::encode(wallet.credential().to_bytes()); + if format_json { + accounts.as_array_mut().unwrap().push(json!({ + "address": format!("{}", wallet.address()), + "private_key": format!("0x{}", private_key), + })); + } else { + sh_println!("- Account {i}:")?; + sh_println!("Address: {}", wallet.address())?; + sh_println!("Private key: 0x{private_key}\n")?; + } + } + + if format_json { + let obj = json!({ + "mnemonic": phrase, + "accounts": accounts, + }); + sh_println!("{}", serde_json::to_string_pretty(&obj)?)?; } } Self::Vanity(cmd) => { @@ -330,7 +351,7 @@ impl WalletSubcommands { .signer() .await?; let addr = wallet.address(); - println!("{}", addr.to_checksum(None)); + sh_println!("{}", addr.to_checksum(None))?; } Self::Sign { message, data, from_file, no_hash, wallet } => { let wallet = wallet.signer().await?; @@ -348,7 +369,7 @@ impl WalletSubcommands { } else { wallet.sign_message(&Self::hex_str_to_bytes(&message)?).await? }; - println!("0x{}", hex::encode(sig.as_bytes())); + sh_println!("0x{}", hex::encode(sig.as_bytes()))?; } Self::SignAuth { rpc, nonce, chain, wallet, address } => { let wallet = wallet.signer().await?; @@ -363,15 +384,15 @@ impl WalletSubcommands { } else { provider.get_chain_id().await? }; - let auth = Authorization { chain_id: U256::from(chain_id), address, nonce }; + let auth = Authorization { chain_id, address, nonce }; let signature = wallet.sign_hash(&auth.signature_hash()).await?; let auth = auth.into_signed(signature); - println!("{}", hex::encode_prefixed(alloy_rlp::encode(&auth))); + sh_println!("{}", hex::encode_prefixed(alloy_rlp::encode(&auth)))?; } Self::Verify { message, signature, address } => { let recovered_address = Self::recover_address_from_message(&message, &signature)?; if address == recovered_address { - println!("Validation succeeded. Address {address} signed this message."); + sh_println!("Validation succeeded. Address {address} signed this message.")?; } else { eyre::bail!("Validation failed. Address {address} did not sign this message."); } @@ -432,7 +453,7 @@ flag to set your key via: "`{}` keystore was saved successfully. Address: {:?}", &account_name, address, ); - println!("{}", success_message.green()); + sh_println!("{}", success_message.green())?; } Self::List(cmd) => { cmd.run().await?; @@ -465,13 +486,13 @@ flag to set your key via: match wallet { WalletSigner::Local(wallet) => { if verbose { - println!("Address: {}", wallet.address()); - println!( + sh_println!("Address: {}", wallet.address())?; + sh_println!( "Private key: 0x{}", hex::encode(wallet.credential().to_bytes()) - ); + )?; } else { - println!("0x{}", hex::encode(wallet.credential().to_bytes())); + sh_println!("0x{}", hex::encode(wallet.credential().to_bytes()))?; } } _ => { @@ -509,7 +530,7 @@ flag to set your key via: let success_message = format!("{}'s private key is: {}", &account_name, private_key); - println!("{}", success_message.green()); + sh_println!("{}", success_message.green())?; } }; diff --git a/crates/cast/bin/cmd/wallet/vanity.rs b/crates/cast/bin/cmd/wallet/vanity.rs index 5b597b3f0..2137feb42 100644 --- a/crates/cast/bin/cmd/wallet/vanity.rs +++ b/crates/cast/bin/cmd/wallet/vanity.rs @@ -3,6 +3,7 @@ use alloy_signer::{k256::ecdsa::SigningKey, utils::secret_key_to_address}; use alloy_signer_local::PrivateKeySigner; use clap::Parser; use eyre::Result; +use foundry_common::sh_println; use itertools::Either; use rayon::iter::{self, ParallelIterator}; use regex::Regex; @@ -99,7 +100,7 @@ impl VanityArgs { }; } - println!("Starting to generate vanity address..."); + sh_println!("Starting to generate vanity address...")?; let timer = Instant::now(); let wallet = match (left_exact_hex, left_regex, right_exact_hex, right_regex) { @@ -144,7 +145,7 @@ impl VanityArgs { save_wallet_to_file(&wallet, &save_path)?; } - println!( + sh_println!( "Successfully found vanity address in {:.3} seconds.{}{}\nAddress: {}\nPrivate Key: 0x{}", timer.elapsed().as_secs_f64(), if nonce.is_some() { "\nContract address: " } else { "" }, @@ -155,7 +156,7 @@ impl VanityArgs { }, wallet.address().to_checksum(None), hex::encode(wallet.credential().to_bytes()), - ); + )?; Ok(wallet) } diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index 63894d980..851fcfd77 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -8,7 +8,7 @@ use cast::{Cast, SimpleCast}; use clap::{CommandFactory, Parser}; use clap_complete::generate; use eyre::Result; -use foundry_cli::{handler, prompt, stdin, utils}; +use foundry_cli::{handler, utils}; use foundry_common::{ abi::get_event, ens::{namehash, ProviderEnsExt}, @@ -19,6 +19,7 @@ use foundry_common::{ import_selectors, parse_signatures, pretty_calldata, ParsedSignatures, SelectorImportData, SelectorType, }, + shell, stdin, }; use foundry_config::Config; use std::time::Instant; @@ -29,16 +30,27 @@ pub mod tx; use args::{Cast as CastArgs, CastSubcommand, ToBaseArgs}; +#[macro_use] +extern crate foundry_common; + #[cfg(all(feature = "jemalloc", unix))] #[global_allocator] static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; -fn main() -> Result<()> { +fn main() { + if let Err(err) = run() { + let _ = foundry_common::sh_err!("{err:?}"); + std::process::exit(1); + } +} + +fn run() -> Result<()> { handler::install(); utils::load_dotenv(); utils::subscriber(); utils::enable_paint(); let args = CastArgs::parse(); + args.shell.shell().set(); main_args(args) } @@ -48,53 +60,53 @@ async fn main_args(args: CastArgs) -> Result<()> { match args.cmd { // Constants CastSubcommand::MaxInt { r#type } => { - println!("{}", SimpleCast::max_int(&r#type)?); + sh_println!("{}", SimpleCast::max_int(&r#type)?)?; } CastSubcommand::MinInt { r#type } => { - println!("{}", SimpleCast::min_int(&r#type)?); + sh_println!("{}", SimpleCast::min_int(&r#type)?)?; } CastSubcommand::MaxUint { r#type } => { - println!("{}", SimpleCast::max_int(&r#type)?); + sh_println!("{}", SimpleCast::max_int(&r#type)?)?; } CastSubcommand::AddressZero => { - println!("{:?}", Address::ZERO); + sh_println!("{:?}", Address::ZERO)?; } CastSubcommand::HashZero => { - println!("{:?}", B256::ZERO); + sh_println!("{:?}", B256::ZERO)?; } // Conversions & transformations CastSubcommand::FromUtf8 { text } => { let value = stdin::unwrap(text, false)?; - println!("{}", SimpleCast::from_utf8(&value)); + sh_println!("{}", SimpleCast::from_utf8(&value))? } CastSubcommand::ToAscii { hexdata } => { let value = stdin::unwrap(hexdata, false)?; - println!("{}", SimpleCast::to_ascii(value.trim())?); + sh_println!("{}", SimpleCast::to_ascii(value.trim())?)? } CastSubcommand::ToUtf8 { hexdata } => { let value = stdin::unwrap(hexdata, false)?; - println!("{}", SimpleCast::to_utf8(&value)?); + sh_println!("{}", SimpleCast::to_utf8(&value)?)? } CastSubcommand::FromFixedPoint { value, decimals } => { let (value, decimals) = stdin::unwrap2(value, decimals)?; - println!("{}", SimpleCast::from_fixed_point(&value, &decimals)?); + sh_println!("{}", SimpleCast::from_fixed_point(&value, &decimals)?)? } CastSubcommand::ToFixedPoint { value, decimals } => { let (value, decimals) = stdin::unwrap2(value, decimals)?; - println!("{}", SimpleCast::to_fixed_point(&value, &decimals)?); + sh_println!("{}", SimpleCast::to_fixed_point(&value, &decimals)?)? } CastSubcommand::ConcatHex { data } => { if data.is_empty() { let s = stdin::read(true)?; - println!("{}", SimpleCast::concat_hex(s.split_whitespace())) + sh_println!("{}", SimpleCast::concat_hex(s.split_whitespace()))? } else { - println!("{}", SimpleCast::concat_hex(data)) + sh_println!("{}", SimpleCast::concat_hex(data))? } } CastSubcommand::FromBin => { let hex = stdin::read_bytes(false)?; - println!("{}", hex::encode_prefixed(hex)); + sh_println!("{}", hex::encode_prefixed(hex))? } CastSubcommand::ToHexdata { input } => { let value = stdin::unwrap_line(input)?; @@ -103,106 +115,120 @@ async fn main_args(args: CastArgs) -> Result<()> { s if s.starts_with('/') => hex::encode(fs::read(s)?), s => s.split(':').map(|s| s.trim_start_matches("0x").to_lowercase()).collect(), }; - println!("0x{output}"); + sh_println!("0x{output}")? } CastSubcommand::ToCheckSumAddress { address } => { let value = stdin::unwrap_line(address)?; - println!("{}", value.to_checksum(None)); + sh_println!("{}", value.to_checksum(None))? } CastSubcommand::ToUint256 { value } => { let value = stdin::unwrap_line(value)?; - println!("{}", SimpleCast::to_uint256(&value)?); + sh_println!("{}", SimpleCast::to_uint256(&value)?)? } CastSubcommand::ToInt256 { value } => { let value = stdin::unwrap_line(value)?; - println!("{}", SimpleCast::to_int256(&value)?); + sh_println!("{}", SimpleCast::to_int256(&value)?)? } CastSubcommand::ToUnit { value, unit } => { let value = stdin::unwrap_line(value)?; - println!("{}", SimpleCast::to_unit(&value, &unit)?); + sh_println!("{}", SimpleCast::to_unit(&value, &unit)?)? + } + CastSubcommand::ParseUnits { value, unit } => { + let value = stdin::unwrap_line(value)?; + println!("{}", SimpleCast::parse_units(&value, unit)?); + } + CastSubcommand::FormatUnits { value, unit } => { + let value = stdin::unwrap_line(value)?; + println!("{}", SimpleCast::format_units(&value, unit)?); } CastSubcommand::FromWei { value, unit } => { let value = stdin::unwrap_line(value)?; - println!("{}", SimpleCast::from_wei(&value, &unit)?); + sh_println!("{}", SimpleCast::from_wei(&value, &unit)?)? } CastSubcommand::ToWei { value, unit } => { let value = stdin::unwrap_line(value)?; - println!("{}", SimpleCast::to_wei(&value, &unit)?); + sh_println!("{}", SimpleCast::to_wei(&value, &unit)?)? } - CastSubcommand::FromRlp { value } => { + CastSubcommand::FromRlp { value, as_int } => { let value = stdin::unwrap_line(value)?; - println!("{}", SimpleCast::from_rlp(value)?); + sh_println!("{}", SimpleCast::from_rlp(value, as_int)?)? } CastSubcommand::ToRlp { value } => { let value = stdin::unwrap_line(value)?; - println!("{}", SimpleCast::to_rlp(&value)?); + sh_println!("{}", SimpleCast::to_rlp(&value)?)? } CastSubcommand::ToHex(ToBaseArgs { value, base_in }) => { let value = stdin::unwrap_line(value)?; - println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), "hex")?); + sh_println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), "hex")?)? } CastSubcommand::ToDec(ToBaseArgs { value, base_in }) => { let value = stdin::unwrap_line(value)?; - println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), "dec")?); + sh_println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), "dec")?)? } CastSubcommand::ToBase { base: ToBaseArgs { value, base_in }, base_out } => { let (value, base_out) = stdin::unwrap2(value, base_out)?; - println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), &base_out)?); + sh_println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), &base_out)?)? } CastSubcommand::ToBytes32 { bytes } => { let value = stdin::unwrap_line(bytes)?; - println!("{}", SimpleCast::to_bytes32(&value)?); + sh_println!("{}", SimpleCast::to_bytes32(&value)?)? } CastSubcommand::FormatBytes32String { string } => { let value = stdin::unwrap_line(string)?; - println!("{}", SimpleCast::format_bytes32_string(&value)?); + sh_println!("{}", SimpleCast::format_bytes32_string(&value)?)? } CastSubcommand::ParseBytes32String { bytes } => { let value = stdin::unwrap_line(bytes)?; - println!("{}", SimpleCast::parse_bytes32_string(&value)?); + sh_println!("{}", SimpleCast::parse_bytes32_string(&value)?)? } CastSubcommand::ParseBytes32Address { bytes } => { let value = stdin::unwrap_line(bytes)?; - println!("{}", SimpleCast::parse_bytes32_address(&value)?); + sh_println!("{}", SimpleCast::parse_bytes32_address(&value)?)? } // ABI encoding & decoding - CastSubcommand::AbiDecode { sig, calldata, input, json } => { + CastSubcommand::AbiDecode { sig, calldata, input } => { let tokens = SimpleCast::abi_decode(&sig, &calldata, input)?; - print_tokens(&tokens, json) + print_tokens(&tokens, shell::is_json()) } CastSubcommand::AbiEncode { sig, packed, args } => { if !packed { - println!("{}", SimpleCast::abi_encode(&sig, &args)?); + sh_println!("{}", SimpleCast::abi_encode(&sig, &args)?)? } else { - println!("{}", SimpleCast::abi_encode_packed(&sig, &args)?); + sh_println!("{}", SimpleCast::abi_encode_packed(&sig, &args)?)? } } - CastSubcommand::CalldataDecode { sig, calldata, json } => { + CastSubcommand::CalldataDecode { sig, calldata } => { let tokens = SimpleCast::calldata_decode(&sig, &calldata, true)?; - print_tokens(&tokens, json) + print_tokens(&tokens, shell::is_json()) } CastSubcommand::CalldataEncode { sig, args } => { - println!("{}", SimpleCast::calldata_encode(sig, &args)?); + sh_println!("{}", SimpleCast::calldata_encode(sig, &args)?)?; + } + CastSubcommand::StringDecode { data } => { + let tokens = SimpleCast::calldata_decode("Any(string)", &data, true)?; + print_tokens(&tokens, shell::is_json()) } CastSubcommand::Interface(cmd) => cmd.run().await?, + CastSubcommand::CreationCode(cmd) => cmd.run().await?, + CastSubcommand::ConstructorArgs(cmd) => cmd.run().await?, CastSubcommand::Bind(cmd) => cmd.run().await?, CastSubcommand::PrettyCalldata { calldata, offline } => { let calldata = stdin::unwrap_line(calldata)?; - println!("{}", pretty_calldata(&calldata, offline).await?); + sh_println!("{}", pretty_calldata(&calldata, offline).await?)?; } CastSubcommand::Sig { sig, optimize } => { let sig = stdin::unwrap_line(sig)?; match optimize { Some(opt) => { - println!("Starting to optimize signature..."); + sh_println!("Starting to optimize signature...")?; let start_time = Instant::now(); let (selector, signature) = SimpleCast::get_selector(&sig, opt)?; - println!("Successfully generated in {:?}", start_time.elapsed()); - println!("Selector: {selector}"); - println!("Optimized signature: {signature}"); + sh_println!("Successfully generated in {:?}", start_time.elapsed())?; + sh_println!("Selector: {selector}")?; + sh_println!("Optimized signature: {signature}")?; } - None => println!("{}", SimpleCast::get_selector(&sig, 0)?.0), + None => sh_println!("{}", SimpleCast::get_selector(&sig, 0)?.0)?, } } @@ -211,10 +237,10 @@ async fn main_args(args: CastArgs) -> Result<()> { CastSubcommand::Age { block, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; - println!( + sh_println!( "{}", Cast::new(provider).age(block.unwrap_or(BlockId::Number(Latest))).await? - ); + )? } CastSubcommand::Balance { block, who, ether, rpc, erc20 } => { let config = Config::from(&rpc); @@ -225,14 +251,14 @@ async fn main_args(args: CastArgs) -> Result<()> { Some(token) => { let balance = Cast::new(&provider).erc20_balance(token, account_addr, block).await?; - println!("{}", format_uint_exp(balance)); + sh_println!("{}", format_uint_exp(balance))? } None => { let value = Cast::new(&provider).balance(account_addr, block).await?; if ether { - println!("{}", SimpleCast::from_wei(&value.to_string(), "eth")?); + sh_println!("{}", SimpleCast::from_wei(&value.to_string(), "eth")?)? } else { - println!("{value}"); + sh_println!("{value}")? } } } @@ -240,20 +266,20 @@ async fn main_args(args: CastArgs) -> Result<()> { CastSubcommand::BaseFee { block, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; - println!( + sh_println!( "{}", Cast::new(provider).base_fee(block.unwrap_or(BlockId::Number(Latest))).await? - ); + )? } - CastSubcommand::Block { block, full, field, json, rpc } => { + CastSubcommand::Block { block, full, field, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; - println!( + sh_println!( "{}", Cast::new(provider) - .block(block.unwrap_or(BlockId::Number(Latest)), full, field, json) + .block(block.unwrap_or(BlockId::Number(Latest)), full, field) .await? - ); + )? } CastSubcommand::BlockNumber { rpc, block } => { let config = Config::from(&rpc); @@ -269,34 +295,34 @@ async fn main_args(args: CastArgs) -> Result<()> { } None => Cast::new(provider).block_number().await?, }; - println!("{number}"); + sh_println!("{number}")? } CastSubcommand::Chain { rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; - println!("{}", Cast::new(provider).chain().await?); + sh_println!("{}", Cast::new(provider).chain().await?)? } CastSubcommand::ChainId { rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; - println!("{}", Cast::new(provider).chain_id().await?); + sh_println!("{}", Cast::new(provider).chain_id().await?)? } CastSubcommand::Client { rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; - println!("{}", provider.get_client_version().await?); + sh_println!("{}", provider.get_client_version().await?)? } CastSubcommand::Code { block, who, disassemble, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let who = who.resolve(&provider).await?; - println!("{}", Cast::new(provider).code(who, block, disassemble).await?); + sh_println!("{}", Cast::new(provider).code(who, block, disassemble).await?)? } CastSubcommand::Codesize { block, who, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let who = who.resolve(&provider).await?; - println!("{}", Cast::new(provider).codesize(who, block).await?); + sh_println!("{}", Cast::new(provider).codesize(who, block).await?)? } CastSubcommand::ComputeAddress { address, nonce, rpc } => { let config = Config::from(&rpc); @@ -304,10 +330,10 @@ async fn main_args(args: CastArgs) -> Result<()> { let address: Address = stdin::unwrap_line(address)?.parse()?; let computed = Cast::new(provider).compute_address(address, nonce).await?; - println!("Computed Address: {}", computed.to_checksum(None)); + sh_println!("Computed Address: {}", computed.to_checksum(None))? } CastSubcommand::Disassemble { bytecode } => { - println!("{}", SimpleCast::disassemble(&hex::decode(bytecode)?)?); + sh_println!("{}", SimpleCast::disassemble(&hex::decode(bytecode)?)?)? } CastSubcommand::Selectors { bytecode, resolve } => { let functions = SimpleCast::extract_functions(&bytecode)?; @@ -325,9 +351,9 @@ async fn main_args(args: CastArgs) -> Result<()> { { if resolve { let resolved = &resolve_results[pos]; - println!("{selector}\t{arguments:max_args_len$}\t{state_mutability:max_mutability_len$}\t{resolved}"); + sh_println!("{selector}\t{arguments:max_args_len$}\t{state_mutability:max_mutability_len$}\t{resolved}")? } else { - println!("{selector}\t{arguments:max_args_len$}\t{state_mutability}"); + sh_println!("{selector}\t{arguments:max_args_len$}\t{state_mutability}")? } } } @@ -335,45 +361,45 @@ async fn main_args(args: CastArgs) -> Result<()> { CastSubcommand::GasPrice { rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; - println!("{}", Cast::new(provider).gas_price().await?); + sh_println!("{}", Cast::new(provider).gas_price().await?)?; } CastSubcommand::Index { key_type, key, slot_number } => { - println!("{}", SimpleCast::index(&key_type, &key, &slot_number)?); + sh_println!("{}", SimpleCast::index(&key_type, &key, &slot_number)?)?; } CastSubcommand::IndexErc7201 { id, formula_id } => { eyre::ensure!(formula_id == "erc7201", "unsupported formula ID: {formula_id}"); let id = stdin::unwrap_line(id)?; - println!("{}", foundry_common::erc7201(&id)); + sh_println!("{}", foundry_common::erc7201(&id))?; } CastSubcommand::Implementation { block, who, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let who = who.resolve(&provider).await?; - println!("{}", Cast::new(provider).implementation(who, block).await?); + sh_println!("{}", Cast::new(provider).implementation(who, block).await?)?; } CastSubcommand::Admin { block, who, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let who = who.resolve(&provider).await?; - println!("{}", Cast::new(provider).admin(who, block).await?); + sh_println!("{}", Cast::new(provider).admin(who, block).await?)?; } CastSubcommand::Nonce { block, who, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let who = who.resolve(&provider).await?; - println!("{}", Cast::new(provider).nonce(who, block).await?); + sh_println!("{}", Cast::new(provider).nonce(who, block).await?)?; } CastSubcommand::Codehash { block, who, slots, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let who = who.resolve(&provider).await?; - println!("{}", Cast::new(provider).codehash(who, slots, block).await?); + sh_println!("{}", Cast::new(provider).codehash(who, slots, block).await?)?; } CastSubcommand::StorageRoot { block, who, slots, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; let who = who.resolve(&provider).await?; - println!("{}", Cast::new(provider).storage_root(who, slots, block).await?); + sh_println!("{}", Cast::new(provider).storage_root(who, slots, block).await?)?; } CastSubcommand::Proof { address, slots, rpc, block } => { let config = Config::from(&rpc); @@ -383,7 +409,7 @@ async fn main_args(args: CastArgs) -> Result<()> { .get_proof(address, slots.into_iter().collect()) .block_id(block.unwrap_or_default()) .await?; - println!("{}", serde_json::to_string(&value)?); + sh_println!("{}", serde_json::to_string(&value)?)?; } CastSubcommand::Rpc(cmd) => cmd.run().await?, CastSubcommand::Storage(cmd) => cmd.run().await?, @@ -400,32 +426,32 @@ async fn main_args(args: CastArgs) -> Result<()> { let tx_hash = pending_tx.inner().tx_hash(); if cast_async { - println!("{tx_hash:#x}"); + sh_println!("{tx_hash:#x}")?; } else { let receipt = pending_tx.get_receipt().await?; - println!("{}", serde_json::json!(receipt)); + sh_println!("{}", serde_json::json!(receipt))?; } } - CastSubcommand::Receipt { tx_hash, field, json, cast_async, confirmations, rpc } => { + CastSubcommand::Receipt { tx_hash, field, cast_async, confirmations, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; - println!( + sh_println!( "{}", Cast::new(provider) - .receipt(tx_hash, field, confirmations, None, cast_async, json) + .receipt(tx_hash, field, confirmations, None, cast_async) .await? - ); + )? } CastSubcommand::Run(cmd) => cmd.run().await?, CastSubcommand::SendTx(cmd) => cmd.run().await?, - CastSubcommand::Tx { tx_hash, field, raw, json, rpc } => { + CastSubcommand::Tx { tx_hash, field, raw, rpc } => { let config = Config::from(&rpc); let provider = utils::get_provider(&config)?; // Can use either --raw or specify raw as a field let raw = raw || field.as_ref().is_some_and(|f| f == "raw"); - println!("{}", Cast::new(&provider).transaction(tx_hash, field, raw, json).await?) + sh_println!("{}", Cast::new(&provider).transaction(tx_hash, field, raw).await?)? } // 4Byte @@ -436,13 +462,15 @@ async fn main_args(args: CastArgs) -> Result<()> { eyre::bail!("No matching function signatures found for selector `{selector}`"); } for sig in sigs { - println!("{sig}"); + sh_println!("{sig}")? } } - CastSubcommand::FourByteDecode { calldata, json } => { + CastSubcommand::FourByteDecode { calldata } => { let calldata = stdin::unwrap_line(calldata)?; let sigs = decode_calldata(&calldata).await?; - sigs.iter().enumerate().for_each(|(i, sig)| println!("{}) \"{sig}\"", i + 1)); + sigs.iter().enumerate().for_each(|(i, sig)| { + let _ = sh_println!("{}) \"{sig}\"", i + 1); + }); let sig = match sigs.len() { 0 => eyre::bail!("No signatures found"), @@ -454,7 +482,7 @@ async fn main_args(args: CastArgs) -> Result<()> { }; let tokens = SimpleCast::calldata_decode(sig, &calldata, true)?; - print_tokens(&tokens, json) + print_tokens(&tokens, shell::is_json()) } CastSubcommand::FourByteEvent { topic } => { let topic = stdin::unwrap_line(topic)?; @@ -463,7 +491,7 @@ async fn main_args(args: CastArgs) -> Result<()> { eyre::bail!("No matching event signatures found for topic `{topic}`"); } for sig in sigs { - println!("{sig}"); + sh_println!("{sig}")? } } CastSubcommand::UploadSignature { signatures } => { @@ -480,7 +508,7 @@ async fn main_args(args: CastArgs) -> Result<()> { // ENS CastSubcommand::Namehash { name } => { let name = stdin::unwrap_line(name)?; - println!("{}", namehash(&name)); + sh_println!("{}", namehash(&name))? } CastSubcommand::LookupAddress { who, rpc, verify } => { let config = Config::from(&rpc); @@ -495,7 +523,7 @@ async fn main_args(args: CastArgs) -> Result<()> { "Reverse lookup verification failed: got `{address}`, expected `{who}`" ); } - println!("{name}"); + sh_println!("{name}")? } CastSubcommand::ResolveName { who, rpc, verify } => { let config = Config::from(&rpc); @@ -510,7 +538,7 @@ async fn main_args(args: CastArgs) -> Result<()> { "Forward lookup verification failed: got `{name}`, expected `{who}`" ); } - println!("{address}"); + sh_println!("{address}")? } // Misc @@ -522,34 +550,32 @@ async fn main_args(args: CastArgs) -> Result<()> { match String::from_utf8(bytes) { Ok(s) => { let s = SimpleCast::keccak(&s)?; - println!("{s}"); + sh_println!("{s}")? } Err(e) => { let hash = keccak256(e.as_bytes()); let s = hex::encode(hash); - println!("0x{s}"); + sh_println!("0x{s}")? } }; } CastSubcommand::HashMessage { message } => { let message = stdin::unwrap_line(message)?; - let input = match message.strip_prefix("0x") { - Some(hex_str) => hex::decode(hex_str)?, - None => message.as_bytes().to_vec(), - }; - println!("{}", eip191_hash_message(input)); + sh_println!("{}", eip191_hash_message(message))? } CastSubcommand::SigEvent { event_string } => { let event_string = stdin::unwrap_line(event_string)?; let parsed_event = get_event(&event_string)?; - println!("{:?}", parsed_event.selector()); - } - CastSubcommand::LeftShift { value, bits, base_in, base_out } => { - println!("{}", SimpleCast::left_shift(&value, &bits, base_in.as_deref(), &base_out)?); - } - CastSubcommand::RightShift { value, bits, base_in, base_out } => { - println!("{}", SimpleCast::right_shift(&value, &bits, base_in.as_deref(), &base_out)?); - } + sh_println!("{:?}", parsed_event.selector())? + } + CastSubcommand::LeftShift { value, bits, base_in, base_out } => sh_println!( + "{}", + SimpleCast::left_shift(&value, &bits, base_in.as_deref(), &base_out)? + )?, + CastSubcommand::RightShift { value, bits, base_in, base_out } => sh_println!( + "{}", + SimpleCast::right_shift(&value, &bits, base_in.as_deref(), &base_out)? + )?, CastSubcommand::EtherscanSource { address, directory, etherscan, flatten } => { let config = Config::from(ðerscan); let chain = config.chain.unwrap_or_default(); @@ -560,7 +586,7 @@ async fn main_args(args: CastArgs) -> Result<()> { .await? } (None, false) => { - println!("{}", SimpleCast::etherscan_source(chain, address, api_key).await?); + sh_println!("{}", SimpleCast::etherscan_source(chain, address, api_key).await?)? } (dir, true) => { SimpleCast::etherscan_source_flatten(chain, address, api_key, dir).await?; @@ -585,11 +611,11 @@ async fn main_args(args: CastArgs) -> Result<()> { let tx = stdin::unwrap_line(tx)?; let tx = SimpleCast::decode_raw_transaction(&tx)?; - println!("{}", serde_json::to_string_pretty(&tx)?); + sh_println!("{}", serde_json::to_string_pretty(&tx)?)? } CastSubcommand::DecodeEof { eof } => { let eof = stdin::unwrap_line(eof)?; - println!("{}", SimpleCast::decode_eof(&eof)?); + sh_println!("{}", SimpleCast::decode_eof(&eof)?)? } }; Ok(()) diff --git a/crates/cast/bin/tx.rs b/crates/cast/bin/tx.rs index 3bfff7301..cf355d7b5 100644 --- a/crates/cast/bin/tx.rs +++ b/crates/cast/bin/tx.rs @@ -3,23 +3,20 @@ use alloy_json_abi::Function; use alloy_network::{ AnyNetwork, TransactionBuilder, TransactionBuilder4844, TransactionBuilder7702, }; -use alloy_primitives::{hex, Address, Bytes, TxKind, U256}; +use alloy_primitives::{hex, Address, Bytes, TxKind}; use alloy_provider::Provider; -use alloy_rlp::Decodable; use alloy_rpc_types::{AccessList, Authorization, TransactionInput, TransactionRequest}; use alloy_serde::WithOtherFields; use alloy_signer::Signer; use alloy_transport::Transport; -use cast::revm::primitives::SignedAuthorization; -use eyre::{Result, WrapErr}; +use eyre::Result; use foundry_cli::{ - opts::TransactionOpts, + opts::{CliAuthorizationList, TransactionOpts}, utils::{self, parse_function_args}, }; use foundry_common::ens::NameOrAddress; use foundry_config::{Chain, Config}; use foundry_wallets::{WalletOpts, WalletSigner}; -use serde_json; /// Different sender kinds used by [`CastTxBuilder`]. pub enum SenderKind<'a> { @@ -134,10 +131,10 @@ pub struct CastTxBuilder { tx: WithOtherFields, legacy: bool, blob: bool, - auth: Option, + auth: Option, chain: Chain, etherscan_api_key: Option, - access_list: Option>, + access_list: Option>, state: S, _t: std::marker::PhantomData, } @@ -319,24 +316,32 @@ where self.tx.set_from(from); self.tx.set_chain_id(self.chain.id()); - if !fill { - return Ok((self.tx, self.state.func)); - } + let tx_nonce = if let Some(nonce) = self.tx.nonce { + nonce + } else { + let nonce = self.provider.get_transaction_count(from).await?; + if fill { + self.tx.nonce = Some(nonce); + } + nonce + }; - if let Some(access_list) = match self.access_list { + self.resolve_auth(sender, tx_nonce).await?; + + if let Some(access_list) = match self.access_list.take() { None => None, // --access-list provided with no value, call the provider to create it Some(None) => Some(self.provider.create_access_list(&self.tx).await?.access_list), // Access list provided as a string, attempt to parse it - Some(Some(ref s)) => Some( - serde_json::from_str::(s) - .map(AccessList::from) - .wrap_err("Failed to parse access list from string")?, - ), + Some(Some(access_list)) => Some(access_list), } { self.tx.set_access_list(access_list); } + if !fill { + return Ok((self.tx, self.state.func)); + } + if self.legacy && self.tx.gas_price.is_none() { self.tx.gas_price = Some(self.provider.get_gas_price().await?); } @@ -361,16 +366,6 @@ where } } - let nonce = if let Some(nonce) = self.tx.nonce { - nonce - } else { - let nonce = self.provider.get_transaction_count(from).await?; - self.tx.nonce = Some(nonce); - nonce - }; - - self.resolve_auth(sender, nonce).await?; - if self.tx.gas.is_none() { self.tx.gas = Some(self.provider.estimate_gas(&self.tx).await?); } @@ -379,25 +374,24 @@ where } /// Parses the passed --auth value and sets the authorization list on the transaction. - async fn resolve_auth(&mut self, sender: SenderKind<'_>, nonce: u64) -> Result<()> { - let Some(auth) = &self.auth else { return Ok(()) }; - - let auth = hex::decode(auth)?; - let auth = if let Ok(address) = Address::try_from(auth.as_slice()) { - let auth = - Authorization { chain_id: U256::from(self.chain.id()), nonce: nonce + 1, address }; - - let Some(signer) = sender.as_signer() else { - eyre::bail!("No signer available to sign authorization"); - }; - let signature = signer.sign_hash(&auth.signature_hash()).await?; - - auth.into_signed(signature) - } else if let Ok(auth) = SignedAuthorization::decode(&mut auth.as_ref()) { - auth - } else { - eyre::bail!("Failed to decode authorization"); + async fn resolve_auth(&mut self, sender: SenderKind<'_>, tx_nonce: u64) -> Result<()> { + let Some(auth) = self.auth.take() else { return Ok(()) }; + + let auth = match auth { + CliAuthorizationList::Address(address) => { + let auth = + Authorization { chain_id: self.chain.id(), nonce: tx_nonce + 1, address }; + + let Some(signer) = sender.as_signer() else { + eyre::bail!("No signer available to sign authorization"); + }; + let signature = signer.sign_hash(&auth.signature_hash()).await?; + + auth.into_signed(signature) + } + CliAuthorizationList::Signed(auth) => auth, }; + self.tx.set_authorization_list(vec![auth]); Ok(()) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 69f86268b..75272b3b1 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -27,7 +27,7 @@ use foundry_common::{ abi::{encode_function_args, get_func}, compile::etherscan_project, fmt::*, - fs, get_pretty_tx_receipt_attr, TransactionReceiptWithRevertReason, + fs, get_pretty_tx_receipt_attr, shell, TransactionReceiptWithRevertReason, }; use foundry_compilers::flatten::Flattener; use foundry_config::Chain; @@ -56,6 +56,9 @@ mod rlp_converter; use rlp_converter::Item; +#[macro_use] +extern crate foundry_common; + // TODO: CastContract with common contract initializers? Same for CastProviders? sol! { @@ -120,17 +123,16 @@ where /// let tx = TransactionRequest::default().to(to).input(bytes.into()); /// let tx = WithOtherFields::new(tx); /// let cast = Cast::new(alloy_provider); - /// let data = cast.call(&tx, None, None, false).await?; + /// let data = cast.call(&tx, None, None).await?; /// println!("{}", data); /// # Ok(()) /// # } /// ``` - pub async fn call<'a>( + pub async fn call( &self, req: &WithOtherFields, func: Option<&Function>, block: Option, - json: bool, ) -> Result { let res = self.provider.call(req).block(block.unwrap_or_default()).await?; @@ -171,7 +173,7 @@ where // handle case when return type is not specified Ok(if decoded.is_empty() { res.to_string() - } else if json { + } else if shell::is_json() { let tokens = decoded.iter().map(format_token_raw).collect::>(); serde_json::to_string_pretty(&tokens).unwrap() } else { @@ -205,7 +207,7 @@ where /// let tx = TransactionRequest::default().to(to).input(bytes.into()); /// let tx = WithOtherFields::new(tx); /// let cast = Cast::new(&provider); - /// let access_list = cast.access_list(&tx, None, false).await?; + /// let access_list = cast.access_list(&tx, None).await?; /// println!("{}", access_list); /// # Ok(()) /// # } @@ -214,11 +216,10 @@ where &self, req: &WithOtherFields, block: Option, - to_json: bool, ) -> Result { let access_list = self.provider.create_access_list(req).block_id(block.unwrap_or_default()).await?; - let res = if to_json { + let res = if shell::is_json() { serde_json::to_string(&access_list)? } else { let mut s = @@ -279,7 +280,7 @@ where pub async fn send( &self, tx: WithOtherFields, - ) -> Result> { + ) -> Result> { let res = self.provider.send_transaction(tx).await?; Ok(res) @@ -305,7 +306,7 @@ where pub async fn publish( &self, mut raw_tx: String, - ) -> Result> { + ) -> Result> { raw_tx = match raw_tx.strip_prefix("0x") { Some(s) => s.to_string(), None => raw_tx, @@ -326,7 +327,7 @@ where /// let provider = /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; /// let cast = Cast::new(provider); - /// let block = cast.block(5, true, None, false).await?; + /// let block = cast.block(5, true, None).await?; /// println!("{}", block); /// # Ok(()) /// # } @@ -336,7 +337,6 @@ where block: B, full: bool, field: Option, - to_json: bool, ) -> Result { let block = block.into(); if let Some(ref field) = field { @@ -354,7 +354,7 @@ where let block = if let Some(ref field) = field { get_pretty_block_attr(&block, field) .unwrap_or_else(|| format!("{field} is not a valid block field")) - } else if to_json { + } else if shell::is_json() { serde_json::to_value(&block).unwrap().to_string() } else { block.pretty() @@ -371,7 +371,6 @@ where false, // Select only select field Some(field), - false, ) .await?; @@ -405,14 +404,12 @@ where false, // Select only block hash Some(String::from("hash")), - false, ) .await?; Ok(match &genesis_hash[..] { "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" => { - match &(Self::block(self, 1920000, false, Some("hash".to_string()), false).await?)[..] - { + match &(Self::block(self, 1920000, false, Some("hash".to_string())).await?)[..] { "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f" => { "etclive" } @@ -450,7 +447,7 @@ where "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34" => "bsctest", "0x0d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5b" => "bsc", "0x31ced5b9beb7f8782b014660da0cb18cc409f121f408186886e1ca3e8eeca96b" => { - match &(Self::block(self, 1, false, Some(String::from("hash")), false).await?)[..] { + match &(Self::block(self, 1, false, Some(String::from("hash"))).await?)[..] { "0x738639479dc82d199365626f90caa82f7eafcfe9ed354b456fb3d294597ceb53" => { "avalanche-fuji" } @@ -715,7 +712,7 @@ where /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let tx_hash = "0xf8d1713ea15a81482958fb7ddf884baee8d3bcc478c5f2f604e008dc788ee4fc"; - /// let tx = cast.transaction(tx_hash.to_string(), None, false, false).await?; + /// let tx = cast.transaction(tx_hash.to_string(), None, false).await?; /// println!("{}", tx); /// # Ok(()) /// # } @@ -725,7 +722,6 @@ where tx_hash: String, field: Option, raw: bool, - to_json: bool, ) -> Result { let tx_hash = TxHash::from_str(&tx_hash).wrap_err("invalid tx hash")?; let tx = self @@ -739,7 +735,7 @@ where } else if let Some(field) = field { get_pretty_tx_attr(&tx, field.as_str()) .ok_or_else(|| eyre::eyre!("invalid tx field: {}", field.to_string()))? - } else if to_json { + } else if shell::is_json() { // to_value first to sort json object keys serde_json::to_value(&tx)?.to_string() } else { @@ -758,7 +754,7 @@ where /// ProviderBuilder::<_, _, AnyNetwork>::default().on_builtin("http://localhost:8545").await?; /// let cast = Cast::new(provider); /// let tx_hash = "0xf8d1713ea15a81482958fb7ddf884baee8d3bcc478c5f2f604e008dc788ee4fc"; - /// let receipt = cast.receipt(tx_hash.to_string(), None, 1, None, false, false).await?; + /// let receipt = cast.receipt(tx_hash.to_string(), None, 1, None, false).await?; /// println!("{}", receipt); /// # Ok(()) /// # } @@ -770,7 +766,6 @@ where confs: u64, timeout: Option, cast_async: bool, - to_json: bool, ) -> Result { let tx_hash = TxHash::from_str(&tx_hash).wrap_err("invalid tx hash")?; @@ -783,7 +778,7 @@ where if cast_async { eyre::bail!("tx not found: {:?}", tx_hash) } else { - PendingTransactionBuilder::new(self.provider.root(), tx_hash) + PendingTransactionBuilder::new(self.provider.root().clone(), tx_hash) .with_required_confirmations(confs) .with_timeout(timeout.map(Duration::from_secs)) .get_receipt() @@ -799,7 +794,7 @@ where Ok(if let Some(ref field) = field { get_pretty_tx_receipt_attr(&receipt, field) .ok_or_else(|| eyre::eyre!("invalid receipt field: {}", field))? - } else if to_json { + } else if shell::is_json() { // to_value first to sort json object keys serde_json::to_value(&receipt)?.to_string() } else { @@ -875,10 +870,10 @@ where )) } - pub async fn filter_logs(&self, filter: Filter, to_json: bool) -> Result { + pub async fn filter_logs(&self, filter: Filter) -> Result { let logs = self.provider.get_logs(&filter).await?; - let res = if to_json { + let res = if shell::is_json() { serde_json::to_string(&logs)? } else { let mut s = vec![]; @@ -966,16 +961,11 @@ where /// let filter = /// Filter::new().address(Address::from_str("0x00000000006c3852cbEf3e08E8dF289169EdE581")?); /// let mut output = io::stdout(); - /// cast.subscribe(filter, &mut output, false).await?; + /// cast.subscribe(filter, &mut output).await?; /// # Ok(()) /// # } /// ``` - pub async fn subscribe( - &self, - filter: Filter, - output: &mut dyn io::Write, - to_json: bool, - ) -> Result<()> { + pub async fn subscribe(&self, filter: Filter, output: &mut dyn io::Write) -> Result<()> { // Initialize the subscription stream for logs let mut subscription = self.provider.subscribe_logs(&filter).await?.into_stream(); @@ -986,10 +976,11 @@ where None }; + let format_json = shell::is_json(); let to_block_number = filter.get_to_block(); // If output should be JSON, start with an opening bracket - if to_json { + if format_json { write!(output, "[")?; } @@ -1011,7 +1002,7 @@ where }, // Process incoming log log = subscription.next() => { - if to_json { + if format_json { if !first { write!(output, ",")?; } @@ -1034,7 +1025,7 @@ where } // If output was JSON, end with a closing bracket - if to_json { + if format_json { write!(output, "]")?; } @@ -1351,8 +1342,54 @@ impl SimpleCast { .wrap_err("Could not convert to uint")? .0; let unit = unit.parse().wrap_err("could not parse units")?; - let mut formatted = ParseUnits::U256(value).format_units(unit); + Ok(Self::format_unit_as_string(value, unit)) + } + + /// Convert a number into a uint with arbitrary decimals. + /// + /// # Example + /// + /// ``` + /// use cast::SimpleCast as Cast; + /// + /// # fn main() -> eyre::Result<()> { + /// assert_eq!(Cast::parse_units("1.0", 6)?, "1000000"); // USDC (6 decimals) + /// assert_eq!(Cast::parse_units("2.5", 6)?, "2500000"); + /// assert_eq!(Cast::parse_units("1.0", 12)?, "1000000000000"); // 12 decimals + /// assert_eq!(Cast::parse_units("1.23", 3)?, "1230"); // 3 decimals + /// # Ok(()) + /// # } + /// ``` + pub fn parse_units(value: &str, unit: u8) -> Result { + let unit = Unit::new(unit).ok_or_else(|| eyre::eyre!("invalid unit"))?; + + Ok(ParseUnits::parse_units(value, unit)?.to_string()) + } + /// Format a number from smallest unit to decimal with arbitrary decimals. + /// + /// # Example + /// + /// ``` + /// use cast::SimpleCast as Cast; + /// + /// # fn main() -> eyre::Result<()> { + /// assert_eq!(Cast::format_units("1000000", 6)?, "1"); // USDC (6 decimals) + /// assert_eq!(Cast::format_units("2500000", 6)?, "2.500000"); + /// assert_eq!(Cast::format_units("1000000000000", 12)?, "1"); // 12 decimals + /// assert_eq!(Cast::format_units("1230", 3)?, "1.230"); // 3 decimals + /// # Ok(()) + /// # } + /// ``` + pub fn format_units(value: &str, unit: u8) -> Result { + let value = NumberWithBase::parse_int(value, None)?.number(); + let unit = Unit::new(unit).ok_or_else(|| eyre::eyre!("invalid unit"))?; + Ok(Self::format_unit_as_string(value, unit)) + } + + // Helper function to format units as a string + fn format_unit_as_string(value: U256, unit: Unit) -> String { + let mut formatted = ParseUnits::U256(value).format_units(unit); // Trim empty fractional part. if let Some(dot) = formatted.find('.') { let fractional = &formatted[dot + 1..]; @@ -1360,8 +1397,7 @@ impl SimpleCast { formatted = formatted[..dot].to_string(); } } - - Ok(formatted) + formatted } /// Converts wei into an eth amount @@ -1400,23 +1436,31 @@ impl SimpleCast { Ok(ParseUnits::parse_units(value, unit)?.to_string()) } - /// Decodes rlp encoded list with hex data - /// - /// # Example + // Decodes RLP encoded data with validation for canonical integer representation /// + /// # Examples /// ``` /// use cast::SimpleCast as Cast; /// - /// assert_eq!(Cast::from_rlp("0xc0").unwrap(), "[]"); - /// assert_eq!(Cast::from_rlp("0x0f").unwrap(), "\"0x0f\""); - /// assert_eq!(Cast::from_rlp("0x33").unwrap(), "\"0x33\""); - /// assert_eq!(Cast::from_rlp("0xc161").unwrap(), "[\"0x61\"]"); - /// assert_eq!(Cast::from_rlp("0xc26162").unwrap(), "[\"0x61\",\"0x62\"]"); + /// assert_eq!(Cast::from_rlp("0xc0", false).unwrap(), "[]"); + /// assert_eq!(Cast::from_rlp("0x0f", false).unwrap(), "\"0x0f\""); + /// assert_eq!(Cast::from_rlp("0x33", false).unwrap(), "\"0x33\""); + /// assert_eq!(Cast::from_rlp("0xc161", false).unwrap(), "[\"0x61\"]"); + /// assert_eq!(Cast::from_rlp("820002", true).is_err(), true); + /// assert_eq!(Cast::from_rlp("820002", false).unwrap(), "\"0x0002\""); + /// assert_eq!(Cast::from_rlp("00", true).is_err(), true); + /// assert_eq!(Cast::from_rlp("00", false).unwrap(), "\"0x00\""); /// # Ok::<_, eyre::Report>(()) /// ``` - pub fn from_rlp(value: impl AsRef) -> Result { + pub fn from_rlp(value: impl AsRef, as_int: bool) -> Result { let bytes = hex::decode(value.as_ref()).wrap_err("Could not decode hex")?; + + if as_int { + return Ok(U256::decode(&mut &bytes[..])?.to_string()); + } + let item = Item::decode(&mut &bytes[..]).wrap_err("Could not decode rlp")?; + Ok(item.to_string()) } @@ -1947,9 +1991,9 @@ impl SimpleCast { if let Some(path) = output_path { fs::create_dir_all(path.parent().unwrap())?; fs::write(&path, flattened)?; - println!("Flattened file written at {}", path.display()); + sh_println!("Flattened file written at {}", path.display())? } else { - println!("{flattened}"); + sh_println!("{flattened}")? } Ok(()) @@ -2240,7 +2284,7 @@ mod tests { #[test] fn from_rlp() { let rlp = "0xf8b1a02b5df5f0757397573e8ff34a8b987b21680357de1f6c8d10273aa528a851eaca8080a02838ac1d2d2721ba883169179b48480b2ba4f43d70fcf806956746bd9e83f90380a0e46fff283b0ab96a32a7cc375cecc3ed7b6303a43d64e0a12eceb0bc6bd8754980a01d818c1c414c665a9c9a0e0c0ef1ef87cacb380b8c1f6223cb2a68a4b2d023f5808080a0236e8f61ecde6abfebc6c529441f782f62469d8a2cc47b7aace2c136bd3b1ff08080808080"; - let item = Cast::from_rlp(rlp).unwrap(); + let item = Cast::from_rlp(rlp, false).unwrap(); assert_eq!( item, r#"["0x2b5df5f0757397573e8ff34a8b987b21680357de1f6c8d10273aa528a851eaca","0x","0x","0x2838ac1d2d2721ba883169179b48480b2ba4f43d70fcf806956746bd9e83f903","0x","0xe46fff283b0ab96a32a7cc375cecc3ed7b6303a43d64e0a12eceb0bc6bd87549","0x","0x1d818c1c414c665a9c9a0e0c0ef1ef87cacb380b8c1f6223cb2a68a4b2d023f5","0x","0x","0x","0x236e8f61ecde6abfebc6c529441f782f62469d8a2cc47b7aace2c136bd3b1ff0","0x","0x","0x","0x","0x"]"# diff --git a/crates/cast/src/rlp_converter.rs b/crates/cast/src/rlp_converter.rs index 05e3462cb..3f24aa563 100644 --- a/crates/cast/src/rlp_converter.rs +++ b/crates/cast/src/rlp_converter.rs @@ -95,7 +95,8 @@ impl fmt::Display for Item { #[cfg(test)] mod test { use crate::rlp_converter::Item; - use alloy_rlp::Decodable; + use alloy_primitives::hex; + use alloy_rlp::{Bytes, Decodable}; use serde_json::Result as JsonResult; // https://en.wikipedia.org/wiki/Set-theoretic_definition_of_natural_numbers @@ -108,6 +109,7 @@ mod test { } #[test] + #[allow(clippy::disallowed_macros)] fn encode_decode_test() -> alloy_rlp::Result<()> { let parameters = vec![ (1, b"\xc0".to_vec(), Item::Array(vec![])), @@ -149,6 +151,7 @@ mod test { } #[test] + #[allow(clippy::disallowed_macros)] fn deserialize_from_str_test_hex() -> JsonResult<()> { let parameters = vec![ (1, "[\"\"]", Item::Array(vec![Item::Data(vec![])])), @@ -177,4 +180,24 @@ mod test { Ok(()) } + + #[test] + fn rlp_data() { + // + let hex_val_rlp = hex!("820002"); + let item = Item::decode(&mut &hex_val_rlp[..]).unwrap(); + + let data = hex!("0002"); + let encoded = alloy_rlp::encode(&data[..]); + let decoded: Bytes = alloy_rlp::decode_exact(&encoded[..]).unwrap(); + assert_eq!(Item::Data(decoded.to_vec()), item); + + let hex_val_rlp = hex!("00"); + let item = Item::decode(&mut &hex_val_rlp[..]).unwrap(); + + let data = hex!("00"); + let encoded = alloy_rlp::encode(&data[..]); + let decoded: Bytes = alloy_rlp::decode_exact(&encoded[..]).unwrap(); + assert_eq!(Item::Data(decoded.to_vec()), item); + } } diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index a0c466b61..057c72109 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -30,8 +30,29 @@ Commands: ... Options: - -h, --help Print help - -V, --version Print version + -h, --help + Print help (see a summary with '-h') + + -V, --version + Print version + +Display options: + --color + Log messages coloring + + Possible values: + - auto: Intelligently guess whether to use color output (default) + - always: Force color output + - never: Force disable color output + + --json + Format log messages as JSON + + -q, --quiet + Do not print log messages + + --verbose + Use verbose output Find more information in the book: http://book.getfoundry.sh/reference/cast/cast.html @@ -68,6 +89,9 @@ stateRoot [..] timestamp [..] withdrawalsRoot [..] totalDifficulty [..] +blobGasUsed [..] +excessBlobGas [..] +requestsHash [..] transactions: [ ... ] @@ -157,8 +181,7 @@ Validation succeeded. Address 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf signed .args(["wallet", "verify", "-a", address, "other msg", expected]) .assert_failure() .stderr_eq(str![[r#" -Error: -Validation failed. Address 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf did not sign this message. +Error: Validation failed. Address 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf did not sign this message. "#]]); }); @@ -290,9 +313,16 @@ Created new encrypted keystore file: [..] // tests that `cast wallet new-mnemonic --entropy` outputs the expected mnemonic casttest!(wallet_mnemonic_from_entropy, |_prj, cmd| { - cmd.args(["wallet", "new-mnemonic", "--entropy", "0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c"]) - .assert_success() - .stdout_eq(str![[r#" + cmd.args([ + "wallet", + "new-mnemonic", + "--accounts", + "3", + "--entropy", + "0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c", + ]) + .assert_success() + .stdout_eq(str![[r#" Generating mnemonic from provided entropy... Successfully generated a new mnemonic. Phrase: @@ -303,6 +333,48 @@ Accounts: Address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 Private key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +- Account 1: +Address: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 +Private key: 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d + +- Account 2: +Address: 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC +Private key: 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a + + +"#]]); +}); + +// tests that `cast wallet new-mnemonic --json` outputs the expected mnemonic +casttest!(wallet_mnemonic_from_entropy_json, |_prj, cmd| { + cmd.args([ + "wallet", + "new-mnemonic", + "--accounts", + "3", + "--entropy", + "0xdf9bf37e6fcdf9bf37e6fcdf9bf37e3c", + "--json", + ]) + .assert_success() + .stdout_eq(str![[r#" +{ + "mnemonic": "test test test test test test test test test test test junk", + "accounts": [ + { + "address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "private_key": "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" + }, + { + "address": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "private_key": "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" + }, + { + "address": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", + "private_key": "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" + } + ] +} "#]]); }); @@ -891,8 +963,7 @@ casttest!(mktx_requires_to, |_prj, cmd| { "1", ]); cmd.assert_failure().stderr_eq(str![[r#" -Error: -Must specify a recipient address or contract code to deploy +Error: Must specify a recipient address or contract code to deploy "#]]); }); @@ -909,8 +980,7 @@ casttest!(mktx_signer_from_mismatch, |_prj, cmd| { "0x0000000000000000000000000000000000000001", ]); cmd.assert_failure().stderr_eq(str![[r#" -Error: -The specified sender via CLI/env vars does not match the sender configured via +Error: The specified sender via CLI/env vars does not match the sender configured via the hardware wallet's HD Path. Please use the `--hd-path ` parameter to specify the BIP32 Path which corresponds to the sender, or let foundry automatically detect it by not specifying any sender address. @@ -981,8 +1051,7 @@ casttest!(send_requires_to, |_prj, cmd| { "1", ]); cmd.assert_failure().stderr_eq(str![[r#" -Error: -Must specify a recipient address or contract code to deploy +Error: Must specify a recipient address or contract code to deploy "#]]); }); @@ -1039,47 +1108,56 @@ casttest!(storage, |_prj, cmd| { }); // -casttest!(storage_layout, |_prj, cmd| { +casttest!(storage_layout_simple, |_prj, cmd| { cmd.args([ - "storage", - "--rpc-url", - next_rpc_endpoint(NamedChain::Optimism).as_str(), - "--block", - "110000000", - "--etherscan-api-key", - "JQNGFHINKS1W7Y5FRXU4SPBYF43J3NYK46", - "0xB67c152E69217b5aCB85A2e19dF13423351b0E27", - ]) - .assert_success() - .stdout_eq(str![[r#" -| Name | Type | Slot | Offset | Bytes | Value | Hex Value | Contract | -|-------------------------------|-----------------------------------------------------------------|------|--------|-------|---------------------------------------------------|--------------------------------------------------------------------|----------------------------------------------------| -| gov | address | 0 | 0 | 20 | 1352965747418285184211909460723571462248744342032 | 0x000000000000000000000000ecfd15165d994c2766fbe0d6bacdc2e8dedfd210 | contracts/perp/PositionManager.sol:PositionManager | -| _status | uint256 | 1 | 0 | 32 | 1 | 0x0000000000000000000000000000000000000000000000000000000000000001 | contracts/perp/PositionManager.sol:PositionManager | -| admin | address | 2 | 0 | 20 | 1352965747418285184211909460723571462248744342032 | 0x000000000000000000000000ecfd15165d994c2766fbe0d6bacdc2e8dedfd210 | contracts/perp/PositionManager.sol:PositionManager | -| feeCalculator | address | 3 | 0 | 20 | 1297482016264593221714872710065075000476194625473 | 0x000000000000000000000000e3451b170806aab3e24b5cd03a331c1ccdb4d7c1 | contracts/perp/PositionManager.sol:PositionManager | -| oracle | address | 4 | 0 | 20 | 241116142622541106669066767052022920958068430970 | 0x0000000000000000000000002a3c0592dcb58accd346ccee2bb46e3fb744987a | contracts/perp/PositionManager.sol:PositionManager | -| referralStorage | address | 5 | 0 | 20 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/perp/PositionManager.sol:PositionManager | -| minExecutionFee | uint256 | 6 | 0 | 32 | 20000 | 0x0000000000000000000000000000000000000000000000000000000000004e20 | contracts/perp/PositionManager.sol:PositionManager | -| minBlockDelayKeeper | uint256 | 7 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/perp/PositionManager.sol:PositionManager | -| minTimeExecuteDelayPublic | uint256 | 8 | 0 | 32 | 180 | 0x00000000000000000000000000000000000000000000000000000000000000b4 | contracts/perp/PositionManager.sol:PositionManager | -| minTimeCancelDelayPublic | uint256 | 9 | 0 | 32 | 180 | 0x00000000000000000000000000000000000000000000000000000000000000b4 | contracts/perp/PositionManager.sol:PositionManager | -| maxTimeDelay | uint256 | 10 | 0 | 32 | 1800 | 0x0000000000000000000000000000000000000000000000000000000000000708 | contracts/perp/PositionManager.sol:PositionManager | -| isUserExecuteEnabled | bool | 11 | 0 | 1 | 1 | 0x0000000000000000000000000000000000000000000000000000000000000001 | contracts/perp/PositionManager.sol:PositionManager | -| isUserCancelEnabled | bool | 11 | 1 | 1 | 1 | 0x0000000000000000000000000000000000000000000000000000000000000001 | contracts/perp/PositionManager.sol:PositionManager | -| allowPublicKeeper | bool | 11 | 2 | 1 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/perp/PositionManager.sol:PositionManager | -| allowUserCloseOnly | bool | 11 | 3 | 1 | 1 | 0x0000000000000000000000000000000000000000000000000000000000000001 | contracts/perp/PositionManager.sol:PositionManager | -| openPositionRequestKeys | bytes32[] | 12 | 0 | 32 | 9287 | 0x0000000000000000000000000000000000000000000000000000000000002447 | contracts/perp/PositionManager.sol:PositionManager | -| closePositionRequestKeys | bytes32[] | 13 | 0 | 32 | 5782 | 0x0000000000000000000000000000000000000000000000000000000000001696 | contracts/perp/PositionManager.sol:PositionManager | -| openPositionRequestKeysStart | uint256 | 14 | 0 | 32 | 9287 | 0x0000000000000000000000000000000000000000000000000000000000002447 | contracts/perp/PositionManager.sol:PositionManager | -| closePositionRequestKeysStart | uint256 | 15 | 0 | 32 | 5782 | 0x0000000000000000000000000000000000000000000000000000000000001696 | contracts/perp/PositionManager.sol:PositionManager | -| isPositionKeeper | mapping(address => bool) | 16 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/perp/PositionManager.sol:PositionManager | -| openPositionsIndex | mapping(address => uint256) | 17 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/perp/PositionManager.sol:PositionManager | -| openPositionRequests | mapping(bytes32 => struct PositionManager.OpenPositionRequest) | 18 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/perp/PositionManager.sol:PositionManager | -| closePositionsIndex | mapping(address => uint256) | 19 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/perp/PositionManager.sol:PositionManager | -| closePositionRequests | mapping(bytes32 => struct PositionManager.ClosePositionRequest) | 20 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/perp/PositionManager.sol:PositionManager | -| managers | mapping(address => bool) | 21 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/perp/PositionManager.sol:PositionManager | -| approvedManagers | mapping(address => mapping(address => bool)) | 22 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/perp/PositionManager.sol:PositionManager | + "storage", + "--rpc-url", + next_rpc_endpoint(NamedChain::Mainnet).as_str(), + "--block", + "21034138", + "--etherscan-api-key", + next_mainnet_etherscan_api_key().as_str(), + "0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2", + ]) + .assert_success() + .stdout_eq(str![[r#" +| Name | Type | Slot | Offset | Bytes | Value | Hex Value | Contract | +|---------|---------|------|--------|-------|-------|--------------------------------------------------------------------|-----------------------------------------------| +| _owner | address | 0 | 0 | 20 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/Create2Deployer.sol:Create2Deployer | +| _paused | bool | 0 | 20 | 1 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/Create2Deployer.sol:Create2Deployer | + +"#]]); +}); + +// +casttest!(storage_layout_complex, |_prj, cmd| { + cmd.args([ + "storage", + "--rpc-url", + next_rpc_endpoint(NamedChain::Mainnet).as_str(), + "--block", + "21034138", + "--etherscan-api-key", + next_mainnet_etherscan_api_key().as_str(), + "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + ]) + .assert_success() + .stdout_eq(str![[r#" +| Name | Type | Slot | Offset | Bytes | Value | Hex Value | Contract | +|-------------------------------|--------------------------------------------------------------------|------|--------|-------|--------------------------------------------------|--------------------------------------------------------------------|---------------------------------| +| _status | uint256 | 0 | 0 | 32 | 1 | 0x0000000000000000000000000000000000000000000000000000000000000001 | contracts/vault/Vault.sol:Vault | +| _generalPoolsBalances | mapping(bytes32 => struct EnumerableMap.IERC20ToBytes32Map) | 1 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault | +| _nextNonce | mapping(address => uint256) | 2 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault | +| _paused | bool | 3 | 0 | 1 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault | +| _authorizer | contract IAuthorizer | 3 | 1 | 20 | 549683469959765988649777481110995959958745616871 | 0x0000000000000000000000006048a8c631fb7e77eca533cf9c29784e482391e7 | contracts/vault/Vault.sol:Vault | +| _approvedRelayers | mapping(address => mapping(address => bool)) | 4 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault | +| _isPoolRegistered | mapping(bytes32 => bool) | 5 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault | +| _nextPoolNonce | uint256 | 6 | 0 | 32 | 1760 | 0x00000000000000000000000000000000000000000000000000000000000006e0 | contracts/vault/Vault.sol:Vault | +| _minimalSwapInfoPoolsBalances | mapping(bytes32 => mapping(contract IERC20 => bytes32)) | 7 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault | +| _minimalSwapInfoPoolsTokens | mapping(bytes32 => struct EnumerableSet.AddressSet) | 8 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault | +| _twoTokenPoolTokens | mapping(bytes32 => struct TwoTokenPoolsBalance.TwoTokenPoolTokens) | 9 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault | +| _poolAssetManagers | mapping(bytes32 => mapping(contract IERC20 => address)) | 10 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault | +| _internalTokenBalance | mapping(address => mapping(contract IERC20 => uint256)) | 11 | 0 | 32 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 | contracts/vault/Vault.sol:Vault | "#]]); }); @@ -1235,8 +1313,7 @@ casttest!(ens_resolve_no_dot_eth, |_prj, cmd| { cmd.args(["resolve-name", "emo", "--rpc-url", ð_rpc_url, "--verify"]) .assert_failure() .stderr_eq(str![[r#" -Error: -ENS resolver not found for name "emo" +Error: ENS resolver not found for name "emo" "#]]); }); @@ -1251,8 +1328,7 @@ casttest!(index7201, |_prj, cmd| { casttest!(index7201_unknown_formula_id, |_prj, cmd| { cmd.args(["index-erc7201", "test", "--formula-id", "unknown"]).assert_failure().stderr_eq( str![[r#" -Error: -unsupported formula ID: unknown +Error: unsupported formula ID: unknown "#]], ); @@ -1327,7 +1403,108 @@ casttest!(hash_message, |_prj, cmd| { "#]]); cmd.cast_fuse().args(["hash-message", "0x68656c6c6f"]).assert_success().stdout_eq(str![[r#" -0x50b2c43fd39106bafbba0da34fc430e1f91e3c96ea2acee2bc34119f92b37750 +0x83a0870b6c63a71efdd3b2749ef700653d97454152c4b53fa9b102dc430c7c32 + +"#]]); +}); + +casttest!(parse_units, |_prj, cmd| { + cmd.args(["parse-units", "1.5", "6"]).assert_success().stdout_eq(str![[r#" +1500000 + +"#]]); + + cmd.cast_fuse().args(["pun", "1.23", "18"]).assert_success().stdout_eq(str![[r#" +1230000000000000000 + +"#]]); + + cmd.cast_fuse().args(["--parse-units", "1.23", "3"]).assert_success().stdout_eq(str![[r#" +1230 + +"#]]); +}); + +casttest!(string_decode, |_prj, cmd| { + cmd.args(["string-decode", "0x88c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000054753303235000000000000000000000000000000000000000000000000000000"]).assert_success().stdout_eq(str![[r#" +"GS025" + +"#]]); +}); + +casttest!(format_units, |_prj, cmd| { + cmd.args(["format-units", "1000000", "6"]).assert_success().stdout_eq(str![[r#" +1 + +"#]]); + + cmd.cast_fuse().args(["--format-units", "2500000", "6"]).assert_success().stdout_eq(str![[ + r#" +2.500000 + +"# + ]]); + + cmd.cast_fuse().args(["fun", "1230", "3"]).assert_success().stdout_eq(str![[r#" +1.230 + +"#]]); +}); + +// tests that fetches a sample contract creation code +// +casttest!(fetch_creation_code_from_etherscan, |_prj, cmd| { + let eth_rpc_url = next_http_rpc_endpoint(); + cmd.args([ + "creation-code", + "--etherscan-api-key", + &next_mainnet_etherscan_api_key(), + "0x0923cad07f06b2d0e5e49e63b8b35738d4156b95", + "--rpc-url", + eth_rpc_url.as_str(), + ]) + .assert_success() + .stdout_eq(str![[r#" +0x60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122074c61e8e4eefd410ca92eec26e8112ec6e831d0a4bf35718fdd78b45d68220d064736f6c63430008070033 + +"#]]); +}); + +// tests that fetches a sample contract creation args bytes +// +casttest!(fetch_creation_code_only_args_from_etherscan, |_prj, cmd| { + let eth_rpc_url = next_http_rpc_endpoint(); + cmd.args([ + "creation-code", + "--etherscan-api-key", + &next_mainnet_etherscan_api_key(), + "0x6982508145454ce325ddbe47a25d4ec3d2311933", + "--rpc-url", + eth_rpc_url.as_str(), + "--only-args", + ]) + .assert_success() + .stdout_eq(str![[r#" +0x00000000000000000000000000000000000014bddab3e51a57cff87a50000000 + +"#]]); +}); + +// tests that displays a sample contract creation args +// +casttest!(fetch_constructor_args_from_etherscan, |_prj, cmd| { + let eth_rpc_url = next_http_rpc_endpoint(); + cmd.args([ + "constructor-args", + "--etherscan-api-key", + &next_mainnet_etherscan_api_key(), + "0x6982508145454ce325ddbe47a25d4ec3d2311933", + "--rpc-url", + eth_rpc_url.as_str(), + ]) + .assert_success() + .stdout_eq(str![[r#" +0x00000000000000000000000000000000000014bddab3e51a57cff87a50000000 → Uint(420690000000000000000000000000000, 256) "#]]); }); diff --git a/crates/cheatcodes/Cargo.toml b/crates/cheatcodes/Cargo.toml index df3631ed3..255d6e9e3 100644 --- a/crates/cheatcodes/Cargo.toml +++ b/crates/cheatcodes/Cargo.toml @@ -30,6 +30,7 @@ foundry-config.workspace = true foundry-evm-core.workspace = true foundry-evm-traces.workspace = true foundry-wallets.workspace = true +forge-script-sequence.workspace = true foundry-zksync-core.workspace = true foundry-zksync-compiler.workspace = true foundry-zksync-inspectors.workspace = true diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index 34f0fadc2..6eb176d5b 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -125,6 +125,24 @@ "description": "Unknown `forge` execution context." } ] + }, + { + "name": "BroadcastTxType", + "description": "The transaction type (`txType`) of the broadcast.", + "variants": [ + { + "name": "Call", + "description": "Represents a CALL broadcast tx." + }, + { + "name": "Create", + "description": "Represents a CREATE broadcast tx." + }, + { + "name": "Create2", + "description": "Represents a CREATE2 broadcast tx." + } + ] } ], "structs": [ @@ -524,6 +542,37 @@ "description": "The contract address where the opcode is running" } ] + }, + { + "name": "BroadcastTxSummary", + "description": "Represents a transaction's broadcast details.", + "fields": [ + { + "name": "txHash", + "ty": "bytes32", + "description": "The hash of the transaction that was broadcasted" + }, + { + "name": "txType", + "ty": "BroadcastTxType", + "description": "Represent the type of transaction among CALL, CREATE, CREATE2" + }, + { + "name": "contractAddress", + "ty": "address", + "description": "The address of the contract that was called or created.\n This is address of the contract that is created if the txType is CREATE or CREATE2." + }, + { + "name": "blockNumber", + "ty": "uint64", + "description": "The block number the transaction landed in." + }, + { + "name": "success", + "ty": "bool", + "description": "Status of the transaction, retrieved from the transaction receipt." + } + ] } ], "cheatcodes": [ @@ -5251,6 +5300,66 @@ "status": "stable", "safety": "safe" }, + { + "func": { + "id": "getBroadcast", + "description": "Returns the most recent broadcast for the given contract on `chainId` matching `txType`.\nFor example:\nThe most recent deployment can be fetched by passing `txType` as `CREATE` or `CREATE2`.\nThe most recent call can be fetched by passing `txType` as `CALL`.", + "declaration": "function getBroadcast(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary memory);", + "visibility": "external", + "mutability": "", + "signature": "getBroadcast(string,uint64,uint8)", + "selector": "0x3dc90cb3", + "selectorBytes": [ + 61, + 201, + 12, + 179 + ] + }, + "group": "filesystem", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "getBroadcasts_0", + "description": "Returns all broadcasts for the given contract on `chainId` with the specified `txType`.\nSorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber.", + "declaration": "function getBroadcasts(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary[] memory);", + "visibility": "external", + "mutability": "", + "signature": "getBroadcasts(string,uint64,uint8)", + "selector": "0xf7afe919", + "selectorBytes": [ + 247, + 175, + 233, + 25 + ] + }, + "group": "filesystem", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "getBroadcasts_1", + "description": "Returns all broadcasts for the given contract on `chainId`.\nSorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber.", + "declaration": "function getBroadcasts(string memory contractName, uint64 chainId) external returns (BroadcastTxSummary[] memory);", + "visibility": "external", + "mutability": "", + "signature": "getBroadcasts(string,uint64)", + "selector": "0xf2fa4a26", + "selectorBytes": [ + 242, + 250, + 74, + 38 + ] + }, + "group": "filesystem", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "getCode", @@ -5291,6 +5400,66 @@ "status": "stable", "safety": "safe" }, + { + "func": { + "id": "getDeployment_0", + "description": "Returns the most recent deployment for the current `chainId`.", + "declaration": "function getDeployment(string memory contractName) external returns (address deployedAddress);", + "visibility": "external", + "mutability": "", + "signature": "getDeployment(string)", + "selector": "0xa8091d97", + "selectorBytes": [ + 168, + 9, + 29, + 151 + ] + }, + "group": "filesystem", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "getDeployment_1", + "description": "Returns the most recent deployment for the given contract on `chainId`", + "declaration": "function getDeployment(string memory contractName, uint64 chainId) external returns (address deployedAddress);", + "visibility": "external", + "mutability": "", + "signature": "getDeployment(string,uint64)", + "selector": "0x0debd5d6", + "selectorBytes": [ + 13, + 235, + 213, + 214 + ] + }, + "group": "filesystem", + "status": "stable", + "safety": "safe" + }, + { + "func": { + "id": "getDeployments", + "description": "Returns all deployments for the given contract on `chainId`\nSorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber.\nThe most recent deployment is the first element, and the oldest is the last.", + "declaration": "function getDeployments(string memory contractName, uint64 chainId) external returns (address[] memory deployedAddresses);", + "visibility": "external", + "mutability": "", + "signature": "getDeployments(string,uint64)", + "selector": "0x74e133dd", + "selectorBytes": [ + 116, + 225, + 51, + 221 + ] + }, + "group": "filesystem", + "status": "stable", + "safety": "safe" + }, { "func": { "id": "getFoundryVersion", diff --git a/crates/cheatcodes/spec/src/lib.rs b/crates/cheatcodes/spec/src/lib.rs index 662853e9e..eae2ae0ee 100644 --- a/crates/cheatcodes/spec/src/lib.rs +++ b/crates/cheatcodes/spec/src/lib.rs @@ -86,11 +86,13 @@ impl Cheatcodes<'static> { Vm::StorageAccess::STRUCT.clone(), Vm::Gas::STRUCT.clone(), Vm::DebugStep::STRUCT.clone(), + Vm::BroadcastTxSummary::STRUCT.clone(), ]), enums: Cow::Owned(vec![ Vm::CallerMode::ENUM.clone(), Vm::AccountAccessKind::ENUM.clone(), Vm::ForgeContext::ENUM.clone(), + Vm::BroadcastTxType::ENUM.clone(), ]), errors: Vm::VM_ERRORS.iter().copied().cloned().collect(), events: Cow::Borrowed(&[]), diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index 7b86cfdf2..f1e0db3a0 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -283,6 +283,31 @@ interface Vm { address contractAddr; } + /// The transaction type (`txType`) of the broadcast. + enum BroadcastTxType { + /// Represents a CALL broadcast tx. + Call, + /// Represents a CREATE broadcast tx. + Create, + /// Represents a CREATE2 broadcast tx. + Create2 + } + + /// Represents a transaction's broadcast details. + struct BroadcastTxSummary { + /// The hash of the transaction that was broadcasted + bytes32 txHash; + /// Represent the type of transaction among CALL, CREATE, CREATE2 + BroadcastTxType txType; + /// The address of the contract that was called or created. + /// This is address of the contract that is created if the txType is CREATE or CREATE2. + address contractAddress; + /// The block number the transaction landed in. + uint64 blockNumber; + /// Status of the transaction, retrieved from the transaction receipt. + bool success; + } + // ======== EVM ======== /// Gets the address for a given private key. @@ -1692,6 +1717,44 @@ interface Vm { #[cheatcode(group = Filesystem)] function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); + /// Returns the most recent broadcast for the given contract on `chainId` matching `txType`. + /// + /// For example: + /// + /// The most recent deployment can be fetched by passing `txType` as `CREATE` or `CREATE2`. + /// + /// The most recent call can be fetched by passing `txType` as `CALL`. + #[cheatcode(group = Filesystem)] + function getBroadcast(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary memory); + + /// Returns all broadcasts for the given contract on `chainId` with the specified `txType`. + /// + /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. + #[cheatcode(group = Filesystem)] + function getBroadcasts(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary[] memory); + + /// Returns all broadcasts for the given contract on `chainId`. + /// + /// Sorted such that the most recent broadcast is the first element, and the oldest is the last. i.e descending order of BroadcastTxSummary.blockNumber. + #[cheatcode(group = Filesystem)] + function getBroadcasts(string memory contractName, uint64 chainId) external returns (BroadcastTxSummary[] memory); + + /// Returns the most recent deployment for the current `chainId`. + #[cheatcode(group = Filesystem)] + function getDeployment(string memory contractName) external returns (address deployedAddress); + + /// Returns the most recent deployment for the given contract on `chainId` + #[cheatcode(group = Filesystem)] + function getDeployment(string memory contractName, uint64 chainId) external returns (address deployedAddress); + + /// Returns all deployments for the given contract on `chainId` + /// + /// Sorted in descending order of deployment time i.e descending order of BroadcastTxSummary.blockNumber. + /// + /// The most recent deployment is the first element, and the oldest is the last. + #[cheatcode(group = Filesystem)] + function getDeployments(string memory contractName, uint64 chainId) external returns (address[] memory deployedAddresses); + // -------- Foreign Function Interface -------- /// Performs a foreign function call via the terminal. diff --git a/crates/cheatcodes/src/config.rs b/crates/cheatcodes/src/config.rs index 519ceda5e..6c1446bda 100644 --- a/crates/cheatcodes/src/config.rs +++ b/crates/cheatcodes/src/config.rs @@ -38,6 +38,8 @@ pub struct CheatsConfig { pub fs_permissions: FsPermissions, /// Project root pub root: PathBuf, + /// Absolute Path to broadcast dir i.e project_root/broadcast + pub broadcast: PathBuf, /// Paths (directories) where file reading/writing is allowed pub allowed_paths: Vec, /// How the evm was configured by the user @@ -94,6 +96,7 @@ impl CheatsConfig { paths: config.project_paths(), fs_permissions: config.fs_permissions.clone().joined(config.root.as_ref()), root: config.root.0.clone(), + broadcast: config.root.0.clone().join(&config.broadcast), allowed_paths, evm_opts, labels: config.labels.clone(), @@ -225,6 +228,7 @@ impl Default for CheatsConfig { paths: ProjectPathsConfig::builder().build_with_root("./"), fs_permissions: Default::default(), root: Default::default(), + broadcast: Default::default(), allowed_paths: vec![], evm_opts: Default::default(), labels: Default::default(), diff --git a/crates/cheatcodes/src/error.rs b/crates/cheatcodes/src/error.rs index 85be519bf..d459e9274 100644 --- a/crates/cheatcodes/src/error.rs +++ b/crates/cheatcodes/src/error.rs @@ -293,7 +293,6 @@ impl_from!( alloy_primitives::SignatureError, FsPathError, hex::FromHexError, - eyre::Error, BackendError, DatabaseError, jsonpath_lib::JsonPathError, @@ -316,6 +315,17 @@ impl> From> for Error { } } +impl From for Error { + #[inline] + fn from(err: eyre::Report) -> Self { + let mut chained_cause = String::new(); + for cause in err.chain() { + chained_cause.push_str(format!(" {cause};").as_str()); + } + Self::display(chained_cause) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/cheatcodes/src/evm.rs b/crates/cheatcodes/src/evm.rs index 6d1da5ce6..bda24a598 100644 --- a/crates/cheatcodes/src/evm.rs +++ b/crates/cheatcodes/src/evm.rs @@ -781,9 +781,6 @@ impl Cheatcode for stopAndReturnDebugTraceRecordingCall { return Err(Error::from("nothing recorded")) }; - // Revert the tracer config to the one before recording - tracer.update_config(|_config| record_info.original_tracer_config); - // Use the trace nodes to flatten the call trace let root = tracer.traces(); let steps = flatten_call_trace(0, root, record_info.start_node_idx); @@ -791,6 +788,16 @@ impl Cheatcode for stopAndReturnDebugTraceRecordingCall { let debug_steps: Vec = steps.iter().map(|&step| convert_call_trace_to_debug_step(step)).collect(); + // Free up memory by clearing the steps if they are not recorded outside of cheatcode usage. + if !record_info.original_tracer_config.record_steps { + tracer.traces_mut().nodes_mut().iter_mut().for_each(|node| { + node.trace.steps = Vec::new(); + }); + } + + // Revert the tracer config to the one before recording + tracer.update_config(|_config| record_info.original_tracer_config); + // Clean up the recording info ccx.state.record_debug_steps_info = None; diff --git a/crates/cheatcodes/src/evm/fork.rs b/crates/cheatcodes/src/evm/fork.rs index d1474fe99..cf80782e5 100644 --- a/crates/cheatcodes/src/evm/fork.rs +++ b/crates/cheatcodes/src/evm/fork.rs @@ -1,4 +1,7 @@ -use crate::{Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, DatabaseExt, Result, Vm::*}; +use crate::{ + json::json_value_to_token, Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, DatabaseExt, + Result, Vm::*, +}; use alloy_dyn_abi::DynSolValue; use alloy_primitives::{B256, U256}; use alloy_provider::Provider; @@ -379,18 +382,25 @@ fn rpc_call(url: &str, method: &str, params: &str) -> Result { let result = foundry_common::block_on(provider.raw_request(method.to_string().into(), params_json)) .map_err(|err| fmt_err!("{method:?}: {err}"))?; + let result_as_tokens = convert_to_bytes( + &json_value_to_token(&result).map_err(|err| fmt_err!("failed to parse result: {err}"))?, + ); - let result_as_tokens = match crate::json::json_value_to_token(&result) - .map_err(|err| fmt_err!("failed to parse result: {err}"))? - { - // Convert fixed bytes to bytes to prevent encoding issues. + Ok(result_as_tokens.abi_encode()) +} + +/// Convert fixed bytes and address values to bytes in order to prevent encoding issues. +fn convert_to_bytes(token: &DynSolValue) -> DynSolValue { + match token { + // Convert fixed bytes to prevent encoding issues. // See: DynSolValue::FixedBytes(bytes, size) => { - DynSolValue::Bytes(bytes.as_slice()[..size].to_vec()) + DynSolValue::Bytes(bytes.as_slice()[..*size].to_vec()) } DynSolValue::Address(addr) => DynSolValue::Bytes(addr.to_vec()), - val => val, - }; - - Ok(result_as_tokens.abi_encode()) + // Convert tuple values to prevent encoding issues. + // See: + DynSolValue::Tuple(vals) => DynSolValue::Tuple(vals.iter().map(convert_to_bytes).collect()), + val => val.clone(), + } } diff --git a/crates/cheatcodes/src/fs.rs b/crates/cheatcodes/src/fs.rs index b30a13085..a2a4b69a5 100644 --- a/crates/cheatcodes/src/fs.rs +++ b/crates/cheatcodes/src/fs.rs @@ -5,12 +5,16 @@ use crate::{Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, Result, Vm::* use alloy_dyn_abi::DynSolType; use alloy_json_abi::ContractObject; use alloy_primitives::{hex, map::Entry, Bytes, U256}; +use alloy_provider::network::ReceiptResponse; +use alloy_rpc_types::AnyTransactionReceipt; use alloy_sol_types::SolValue; use dialoguer::{Input, Password}; +use forge_script_sequence::{BroadcastReader, TransactionWithMetadata}; use foundry_common::fs; use foundry_config::fs_permissions::FsAccessKind; use foundry_zksync_compiler::ContractType; use revm::interpreter::CreateInputs; +use revm_inspectors::tracing::types::CallKind; use semver::Version; use std::{ io::{BufRead, BufReader, Write}, @@ -637,6 +641,171 @@ fn prompt( } } +impl Cheatcode for getBroadcastCall { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { contractName, chainId, txType } = self; + + let latest_broadcast = latest_broadcast( + contractName, + *chainId, + &state.config.broadcast, + vec![map_broadcast_tx_type(*txType)], + )?; + + Ok(latest_broadcast.abi_encode()) + } +} + +impl Cheatcode for getBroadcasts_0Call { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { contractName, chainId, txType } = self; + + let reader = BroadcastReader::new(contractName.clone(), *chainId, &state.config.broadcast)? + .with_tx_type(map_broadcast_tx_type(*txType)); + + let broadcasts = reader.read()?; + + let summaries = broadcasts + .into_iter() + .flat_map(|broadcast| { + let results = reader.into_tx_receipts(broadcast); + parse_broadcast_results(results) + }) + .collect::>(); + + Ok(summaries.abi_encode()) + } +} + +impl Cheatcode for getBroadcasts_1Call { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { contractName, chainId } = self; + + let reader = BroadcastReader::new(contractName.clone(), *chainId, &state.config.broadcast)?; + + let broadcasts = reader.read()?; + + let summaries = broadcasts + .into_iter() + .flat_map(|broadcast| { + let results = reader.into_tx_receipts(broadcast); + parse_broadcast_results(results) + }) + .collect::>(); + + Ok(summaries.abi_encode()) + } +} + +impl Cheatcode for getDeployment_0Call { + fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { + let Self { contractName } = self; + let chain_id = ccx.ecx.env.cfg.chain_id; + + let latest_broadcast = latest_broadcast( + contractName, + chain_id, + &ccx.state.config.broadcast, + vec![CallKind::Create, CallKind::Create2], + )?; + + Ok(latest_broadcast.contractAddress.abi_encode()) + } +} + +impl Cheatcode for getDeployment_1Call { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { contractName, chainId } = self; + + let latest_broadcast = latest_broadcast( + contractName, + *chainId, + &state.config.broadcast, + vec![CallKind::Create, CallKind::Create2], + )?; + + Ok(latest_broadcast.contractAddress.abi_encode()) + } +} + +impl Cheatcode for getDeploymentsCall { + fn apply(&self, state: &mut Cheatcodes) -> Result { + let Self { contractName, chainId } = self; + + let reader = BroadcastReader::new(contractName.clone(), *chainId, &state.config.broadcast)? + .with_tx_type(CallKind::Create) + .with_tx_type(CallKind::Create2); + + let broadcasts = reader.read()?; + + let summaries = broadcasts + .into_iter() + .flat_map(|broadcast| { + let results = reader.into_tx_receipts(broadcast); + parse_broadcast_results(results) + }) + .collect::>(); + + let deployed_addresses = + summaries.into_iter().map(|summary| summary.contractAddress).collect::>(); + + Ok(deployed_addresses.abi_encode()) + } +} + +fn map_broadcast_tx_type(tx_type: BroadcastTxType) -> CallKind { + match tx_type { + BroadcastTxType::Call => CallKind::Call, + BroadcastTxType::Create => CallKind::Create, + BroadcastTxType::Create2 => CallKind::Create2, + _ => unreachable!("invalid tx type"), + } +} + +fn parse_broadcast_results( + results: Vec<(TransactionWithMetadata, AnyTransactionReceipt)>, +) -> Vec { + results + .into_iter() + .map(|(tx, receipt)| BroadcastTxSummary { + txHash: receipt.transaction_hash, + blockNumber: receipt.block_number.unwrap_or_default(), + txType: match tx.opcode { + CallKind::Call => BroadcastTxType::Call, + CallKind::Create => BroadcastTxType::Create, + CallKind::Create2 => BroadcastTxType::Create2, + _ => unreachable!("invalid tx type"), + }, + contractAddress: tx.contract_address.unwrap_or_default(), + success: receipt.status(), + }) + .collect() +} + +fn latest_broadcast( + contract_name: &String, + chain_id: u64, + broadcast_path: &Path, + filters: Vec, +) -> Result { + let mut reader = BroadcastReader::new(contract_name.clone(), chain_id, broadcast_path)?; + + for filter in filters { + reader = reader.with_tx_type(filter); + } + + let broadcast = reader.read_latest()?; + + let results = reader.into_tx_receipts(broadcast); + + let summaries = parse_broadcast_results(results); + + summaries + .first() + .ok_or_else(|| fmt_err!("no deployment found for {contract_name} on chain {chain_id}")) + .cloned() +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index d09139354..6fd6ee24e 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -30,7 +30,6 @@ use foundry_cheatcodes_common::{ record::RecordAccess, }; use foundry_common::{evm::Breakpoints, TransactionMaybeSigned, SELECTOR_LEN}; -use foundry_config::Config; use foundry_evm_core::{ abi::{Vm::stopExpectSafeMemoryCall, HARDHAT_CONSOLE_ADDRESS}, backend::{DatabaseError, DatabaseExt, LocalForkId, RevertDiagnostic}, @@ -109,7 +108,7 @@ pub trait CheatcodesExecutor { evm.context.evm.inner.journaled_state.depth += 1; // Handle EOF bytecode - let first_frame_or_result = if evm.handler.cfg.spec_id.is_enabled_in(SpecId::PRAGUE_EOF) && + let first_frame_or_result = if evm.handler.cfg.spec_id.is_enabled_in(SpecId::OSAKA) && inputs.scheme == CreateScheme::Create && inputs.init_code.starts_with(&EOF_MAGIC_BYTES) { @@ -1444,25 +1443,23 @@ where { // broadcasting. if ecx_inner.journaled_state.depth == 0 { let sender = ecx_inner.env.tx.caller; - if sender != Config::DEFAULT_SENDER { - let account = match super::evm::journaled_account(ecx_inner, sender) { - Ok(account) => account, - Err(err) => { - return Some(CallOutcome { - result: InterpreterResult { - result: InstructionResult::Revert, - output: err.abi_encode().into(), - gas, - }, - memory_offset: call.return_memory_offset.clone(), - }) - } - }; - let prev = account.info.nonce; - account.info.nonce = prev.saturating_sub(1); + let account = match super::evm::journaled_account(ecx_inner, sender) { + Ok(account) => account, + Err(err) => { + return Some(CallOutcome { + result: InterpreterResult { + result: InstructionResult::Revert, + output: err.abi_encode().into(), + gas, + }, + memory_offset: call.return_memory_offset.clone(), + }) + } + }; + let prev = account.info.nonce; + account.info.nonce = prev.saturating_sub(1); - trace!(target: "cheatcodes", %sender, nonce=account.info.nonce, prev, "corrected nonce"); - } + trace!(target: "cheatcodes", %sender, nonce=account.info.nonce, prev, "corrected nonce"); } if call.target_address == CHEATCODE_ADDRESS { diff --git a/crates/chisel/bin/main.rs b/crates/chisel/bin/main.rs index 704252794..dca99d4a5 100644 --- a/crates/chisel/bin/main.rs +++ b/crates/chisel/bin/main.rs @@ -11,7 +11,7 @@ use clap::{Parser, Subcommand}; use eyre::Context; use foundry_cli::{ handler, - opts::CoreBuildArgs, + opts::{CoreBuildArgs, ShellOpts}, utils::{self, LoadConfig}, }; use foundry_common::{evm::EvmArgs, fs}; @@ -27,6 +27,9 @@ use std::path::PathBuf; use tracing::debug; use yansi::Paint; +#[macro_use] +extern crate foundry_common; + #[cfg(all(feature = "jemalloc", unix))] #[global_allocator] static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; @@ -50,6 +53,9 @@ pub struct Chisel { #[command(subcommand)] pub cmd: Option, + #[clap(flatten)] + pub shell: ShellOpts, + /// Path to a directory containing Solidity files to import, or path to a single Solidity file. /// /// These files will be evaluated before the top-level of the @@ -100,11 +106,19 @@ pub enum ChiselSubcommand { }, } -fn main() -> eyre::Result<()> { +fn main() { + if let Err(err) = run() { + let _ = foundry_common::sh_err!("{err:?}"); + std::process::exit(1); + } +} + +fn run() -> eyre::Result<()> { handler::install(); utils::subscriber(); utils::load_dotenv(); let args = Chisel::parse(); + args.shell.shell().set(); main_args(args) } @@ -137,9 +151,9 @@ async fn main_args(args: Chisel) -> eyre::Result<()> { let sessions = dispatcher.dispatch_command(ChiselCommand::ListSessions, &[]).await; match sessions { DispatchResult::CommandSuccess(Some(session_list)) => { - println!("{session_list}"); + sh_println!("{session_list}")?; } - DispatchResult::CommandFailed(e) => eprintln!("{e}"), + DispatchResult::CommandFailed(e) => sh_err!("{e}")?, _ => panic!("Unexpected result: Please report this bug."), } return Ok(()) @@ -149,7 +163,7 @@ async fn main_args(args: Chisel) -> eyre::Result<()> { match dispatcher.dispatch_command(ChiselCommand::Load, &[id]).await { DispatchResult::CommandSuccess(_) => { /* Continue */ } DispatchResult::CommandFailed(e) => { - eprintln!("{e}"); + sh_err!("{e}")?; return Ok(()) } _ => panic!("Unexpected result! Please report this bug."), @@ -159,7 +173,7 @@ async fn main_args(args: Chisel) -> eyre::Result<()> { if matches!(args.cmd, Some(ChiselSubcommand::View { .. })) { match dispatcher.dispatch_command(ChiselCommand::Source, &[]).await { DispatchResult::CommandSuccess(Some(source)) => { - println!("{source}"); + sh_println!("{source}")?; } _ => panic!("Unexpected result! Please report this bug."), } @@ -168,14 +182,14 @@ async fn main_args(args: Chisel) -> eyre::Result<()> { } Some(ChiselSubcommand::ClearCache) => { match dispatcher.dispatch_command(ChiselCommand::ClearCache, &[]).await { - DispatchResult::CommandSuccess(Some(msg)) => println!("{}", msg.green()), - DispatchResult::CommandFailed(e) => eprintln!("{e}"), + DispatchResult::CommandSuccess(Some(msg)) => sh_println!("{}", msg.green())?, + DispatchResult::CommandFailed(e) => sh_err!("{e}")?, _ => panic!("Unexpected result! Please report this bug."), } return Ok(()) } Some(ChiselSubcommand::Eval { command }) => { - dispatch_repl_line(&mut dispatcher, command).await; + dispatch_repl_line(&mut dispatcher, command).await?; return Ok(()) } None => { /* No chisel subcommand present; Continue */ } @@ -194,7 +208,7 @@ async fn main_args(args: Chisel) -> eyre::Result<()> { } // Print welcome header - println!("Welcome to Chisel! Type `{}` to show available commands.", "!help".green()); + sh_println!("Welcome to Chisel! Type `{}` to show available commands.", "!help".green())?; // Begin Rustyline loop loop { @@ -213,20 +227,20 @@ async fn main_args(args: Chisel) -> eyre::Result<()> { interrupt = false; // Dispatch and match results - let errored = dispatch_repl_line(&mut dispatcher, &line).await; + let errored = dispatch_repl_line(&mut dispatcher, &line).await?; rl.helper_mut().unwrap().set_errored(errored); } Err(ReadlineError::Interrupted) => { if interrupt { break } else { - println!("(To exit, press Ctrl+C again)"); + sh_println!("(To exit, press Ctrl+C again)")?; interrupt = true; } } Err(ReadlineError::Eof) => break, Err(err) => { - println!("Error: {err:?}"); + sh_err!("{err:?}")?; break } } @@ -251,25 +265,25 @@ impl Provider for Chisel { } /// Evaluate a single Solidity line. -async fn dispatch_repl_line(dispatcher: &mut ChiselDispatcher, line: &str) -> bool { +async fn dispatch_repl_line(dispatcher: &mut ChiselDispatcher, line: &str) -> eyre::Result { let r = dispatcher.dispatch(line).await; match &r { DispatchResult::Success(msg) | DispatchResult::CommandSuccess(msg) => { debug!(%line, ?msg, "dispatch success"); if let Some(msg) = msg { - println!("{}", msg.green()); + sh_println!("{}", msg.green())?; } }, - DispatchResult::UnrecognizedCommand(e) => eprintln!("{e}"), + DispatchResult::UnrecognizedCommand(e) => sh_err!("{e}")?, DispatchResult::SolangParserFailed(e) => { - eprintln!("{}", "Compilation error".red()); - eprintln!("{}", format!("{e:?}").red()); + sh_err!("{}", "Compilation error".red())?; + sh_eprintln!("{}", format!("{e:?}").red())?; } - DispatchResult::FileIoError(e) => eprintln!("{}", format!("⚒️ Chisel File IO Error - {e}").red()), - DispatchResult::CommandFailed(msg) | DispatchResult::Failure(Some(msg)) => eprintln!("{}", msg.red()), - DispatchResult::Failure(None) => eprintln!("{}\nPlease Report this bug as a github issue if it persists: https://github.com/foundry-rs/foundry/issues/new/choose", "⚒️ Unknown Chisel Error ⚒️".red()), + DispatchResult::FileIoError(e) => sh_err!("{}", format!("File IO - {e}").red())?, + DispatchResult::CommandFailed(msg) | DispatchResult::Failure(Some(msg)) => sh_err!("{}", msg.red())?, + DispatchResult::Failure(None) => sh_err!("Please report this bug as a github issue if it persists: https://github.com/foundry-rs/foundry/issues/new/choose")?, } - r.is_error() + Ok(r.is_error()) } /// Evaluate multiple Solidity source files contained within a @@ -280,20 +294,20 @@ async fn evaluate_prelude( ) -> eyre::Result<()> { let Some(prelude_dir) = maybe_prelude else { return Ok(()) }; if prelude_dir.is_file() { - println!("{} {}", "Loading prelude source file:".yellow(), prelude_dir.display(),); + sh_println!("{} {}", "Loading prelude source file:".yellow(), prelude_dir.display())?; load_prelude_file(dispatcher, prelude_dir).await?; - println!("{}\n", "Prelude source file loaded successfully!".green()); + sh_println!("{}\n", "Prelude source file loaded successfully!".green())?; } else { let prelude_sources = fs::files_with_ext(&prelude_dir, "sol"); let mut print_success_msg = false; for source_file in prelude_sources { print_success_msg = true; - println!("{} {}", "Loading prelude source file:".yellow(), source_file.display()); + sh_println!("{} {}", "Loading prelude source file:".yellow(), source_file.display())?; load_prelude_file(dispatcher, source_file).await?; } if print_success_msg { - println!("{}\n", "All prelude source files loaded successfully!".green()); + sh_println!("{}\n", "All prelude source files loaded successfully!".green())?; } } Ok(()) @@ -303,7 +317,7 @@ async fn evaluate_prelude( async fn load_prelude_file(dispatcher: &mut ChiselDispatcher, file: PathBuf) -> eyre::Result<()> { let prelude = fs::read_to_string(file) .wrap_err("Could not load source file. Are you sure this path is correct?")?; - dispatch_repl_line(dispatcher, &prelude).await; + dispatch_repl_line(dispatcher, &prelude).await?; Ok(()) } diff --git a/crates/chisel/src/dispatcher.rs b/crates/chisel/src/dispatcher.rs index 22ad242d0..d69de3bf5 100644 --- a/crates/chisel/src/dispatcher.rs +++ b/crates/chisel/src/dispatcher.rs @@ -275,7 +275,7 @@ impl ChiselDispatcher { if let Err(e) = self.session.write() { return DispatchResult::FileIoError(e.into()) } - println!("{}", "Saved current session!".green()); + let _ = sh_println!("{}", "Saved current session!".green()); } // Parse the arguments @@ -426,7 +426,7 @@ impl ChiselDispatcher { if matches!(cmd, ChiselCommand::MemDump) { // Print memory by word (0..mem.len()).step_by(32).for_each(|i| { - println!( + let _ = sh_println!( "{}: {}", format!("[0x{:02x}:0x{:02x}]", i, i + 32).yellow(), hex::encode_prefixed(&mem[i..i + 32]).cyan() @@ -435,7 +435,7 @@ impl ChiselDispatcher { } else { // Print all stack items (0..stack.len()).rev().for_each(|i| { - println!( + let _ = sh_println!( "{}: {}", format!("[{}]", stack.len() - i - 1).yellow(), format!("0x{:02x}", stack[i]).cyan() @@ -712,25 +712,27 @@ impl ChiselDispatcher { // Show console logs, if there are any let decoded_logs = decode_console_logs(&res.logs); if !decoded_logs.is_empty() { - println!("{}", "Logs:".green()); + let _ = sh_println!("{}", "Logs:".green()); for log in decoded_logs { - println!(" {log}"); + let _ = sh_println!(" {log}"); } } } - // If the contract execution failed, continue on without - // updating the source. - DispatchResult::CommandFailed(Self::make_error( - "Failed to execute edited contract!", - )) - } else { - // the code could be compiled, save it - *self.source_mut() = new_session_source; - DispatchResult::CommandSuccess(Some(String::from( - "Successfully edited `run()` function's body!", - ))) + if failed { + // If the contract execution failed, continue on without + // updating the source. + return DispatchResult::CommandFailed(Self::make_error( + "Failed to execute edited contract!", + )); + } } + + // the code could be compiled, save it + *self.source_mut() = new_session_source; + DispatchResult::CommandSuccess(Some(String::from( + "Successfully edited `run()` function's body!", + ))) } Err(_) => { DispatchResult::CommandFailed("The code could not be compiled".to_string()) @@ -828,7 +830,9 @@ impl ChiselDispatcher { // Should change up how this works. match source.inspect(input).await { // Continue and print - Ok((true, Some(res))) => println!("{res}"), + Ok((true, Some(res))) => { + let _ = sh_println!("{res}"); + } Ok((true, None)) => {} // Return successfully Ok((false, res)) => { @@ -857,9 +861,9 @@ impl ChiselDispatcher { // Show console logs, if there are any let decoded_logs = decode_console_logs(&res.logs); if !decoded_logs.is_empty() { - println!("{}", "Logs:".green()); + let _ = sh_println!("{}", "Logs:".green()); for log in decoded_logs { - println!(" {log}"); + let _ = sh_println!(" {log}"); } } @@ -946,12 +950,12 @@ impl ChiselDispatcher { eyre::bail!("Unexpected error: No traces gathered. Please report this as a bug: https://github.com/foundry-rs/foundry/issues/new?assignees=&labels=T-bug&template=BUG-FORM.yml"); } - println!("{}", "Traces:".green()); + sh_println!("{}", "Traces:".green())?; for (kind, trace) in &mut result.traces { // Display all Setup + Execution traces. if matches!(kind, TraceKind::Setup | TraceKind::Execution) { decode_trace_arena(trace, decoder).await?; - println!("{}", render_trace_arena(trace)); + sh_println!("{}", render_trace_arena(trace))?; } } @@ -968,7 +972,7 @@ impl ChiselDispatcher { /// /// A formatted error [String]. pub fn make_error(msg: T) -> String { - format!("{} {}", format!("{CHISEL_CHAR} Chisel Error:").red(), msg.red()) + format!("{}", msg.red()) } } diff --git a/crates/chisel/src/executor.rs b/crates/chisel/src/executor.rs index ccaac8fea..91ed0decc 100644 --- a/crates/chisel/src/executor.rs +++ b/crates/chisel/src/executor.rs @@ -179,7 +179,7 @@ impl SessionSource { Ok((_, res)) => (res, Some(err)), Err(_) => { if self.config.foundry_config.verbosity >= 3 { - eprintln!("Could not inspect: {err}"); + sh_err!("Could not inspect: {err}")?; } return Ok((true, None)) } @@ -207,7 +207,7 @@ impl SessionSource { // we were unable to check the event if self.config.foundry_config.verbosity >= 3 { - eprintln!("Failed eval: {err}"); + sh_err!("Failed eval: {err}")?; } debug!(%err, %input, "failed abi encode input"); @@ -221,9 +221,9 @@ impl SessionSource { } let decoded_logs = decode_console_logs(&res.logs); if !decoded_logs.is_empty() { - println!("{}", "Logs:".green()); + sh_println!("{}", "Logs:".green())?; for log in decoded_logs { - println!(" {log}"); + sh_println!(" {log}")?; } } @@ -1711,12 +1711,12 @@ mod tests { match solc { Ok((v, solc)) => { // successfully installed - eprintln!("found installed Solc v{v} @ {}", solc.solc.display()); + let _ = sh_println!("found installed Solc v{v} @ {}", solc.solc.display()); break } Err(e) => { // try reinstalling - eprintln!("error while trying to re-install Solc v{version}: {e}"); + let _ = sh_err!("error while trying to re-install Solc v{version}: {e}"); let solc = Solc::blocking_install(&version.parse().unwrap()); if solc.map_err(SolcError::from).is_ok() { *is_preinstalled = true; @@ -1755,7 +1755,7 @@ mod tests { if let Err(e) = s.parse() { for err in e { - eprintln!("{}:{}: {}", err.loc.start(), err.loc.end(), err.message); + let _ = sh_eprintln!("{}:{}: {}", err.loc.start(), err.loc.end(), err.message); } let source = s.to_repl_source(); panic!("could not parse input:\n{source}") diff --git a/crates/chisel/src/lib.rs b/crates/chisel/src/lib.rs index 9e7dcc9fb..ccae2db2d 100644 --- a/crates/chisel/src/lib.rs +++ b/crates/chisel/src/lib.rs @@ -1,6 +1,9 @@ #![doc = include_str!("../README.md")] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#[macro_use] +extern crate foundry_common; + pub mod dispatcher; pub mod cmd; diff --git a/crates/chisel/src/session_source.rs b/crates/chisel/src/session_source.rs index f80761e0d..128873167 100644 --- a/crates/chisel/src/session_source.rs +++ b/crates/chisel/src/session_source.rs @@ -98,7 +98,7 @@ impl SessionSourceConfig { SolcReq::Version(version) } else { if !self.foundry_config.offline { - print!("{}", "No solidity versions installed! ".green()); + sh_print!("{}", "No solidity versions installed! ".green())?; } // use default SolcReq::Version(Version::new(0, 8, 19)) @@ -112,7 +112,7 @@ impl SessionSourceConfig { if self.foundry_config.offline { eyre::bail!("can't install missing solc {version} in offline mode") } - println!("{}", format!("Installing solidity version {version}...").green()); + sh_println!("{}", format!("Installing solidity version {version}...").green())?; Solc::blocking_install(&version)? }; Ok(solc) diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index aed78433e..5de4146e5 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -23,10 +23,12 @@ zksync-web3-rs.workspace = true foundry-compilers = { workspace = true, features = ["full"] } +alloy-eips.workspace = true alloy-dyn-abi.workspace = true alloy-json-abi.workspace = true alloy-primitives.workspace = true alloy-provider.workspace = true +alloy-rlp.workspace = true alloy-transport.workspace = true alloy-chains.workspace = true @@ -44,6 +46,7 @@ tokio = { workspace = true, features = ["macros"] } tracing-subscriber = { workspace = true, features = ["registry", "env-filter"] } tracing.workspace = true yansi.workspace = true +serde_json.workspace = true tracing-tracy = { version = "0.11", optional = true } diff --git a/crates/cli/src/handler.rs b/crates/cli/src/handler.rs index 4f69c2ca4..b2fbb49d4 100644 --- a/crates/cli/src/handler.rs +++ b/crates/cli/src/handler.rs @@ -15,7 +15,6 @@ impl EyreHandler for Handler { if f.alternate() { return core::fmt::Debug::fmt(error, f) } - writeln!(f)?; write!(f, "{}", error.red())?; if let Some(cause) = error.source() { diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index 6f5e2f607..9c1fb848e 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -5,10 +5,12 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#[macro_use] +extern crate foundry_common; + #[macro_use] extern crate tracing; pub mod handler; pub mod opts; -pub mod stdin; pub mod utils; diff --git a/crates/cli/src/opts/build/core.rs b/crates/cli/src/opts/build/core.rs index 809f791d6..23f752290 100644 --- a/crates/cli/src/opts/build/core.rs +++ b/crates/cli/src/opts/build/core.rs @@ -105,11 +105,6 @@ pub struct CoreBuildArgs { #[serde(skip)] pub revert_strings: Option, - /// Don't print anything on startup. - #[arg(long, help_heading = "Compiler options")] - #[serde(skip)] - pub silent: bool, - /// Generate build info files. #[arg(long, help_heading = "Project options")] #[serde(skip)] diff --git a/crates/cli/src/opts/build/zksync.rs b/crates/cli/src/opts/build/zksync.rs index acb4891a9..6ea6da550 100644 --- a/crates/cli/src/opts/build/zksync.rs +++ b/crates/cli/src/opts/build/zksync.rs @@ -1,6 +1,7 @@ -use std::path::PathBuf; +use std::{collections::HashSet, path::PathBuf}; use clap::Parser; +use foundry_compilers::zksolc::settings::{ZkSolcError, ZkSolcWarning}; use foundry_config::ZkSyncConfig; use serde::Serialize; use zksync_web3_rs::types::{Address, Bytes}; @@ -121,6 +122,26 @@ pub struct ZkSyncArgs { visible_alias = "paymaster-input" )] pub paymaster_input: Option, + + /// Set the warnings to suppress for zksolc. + #[clap( + long = "zk-suppressed-warnings", + visible_alias = "suppressed-warnings", + value_delimiter = ',', + help = "Set the warnings to suppress for zksolc, possible values: [txorigin]" + )] + #[serde(skip_serializing_if = "Option::is_none")] + pub suppressed_warnings: Option>, + + /// Set the errors to suppress for zksolc. + #[clap( + long = "zk-suppressed-errors", + visible_alias = "suppressed-errors", + value_delimiter = ',', + help = "Set the errors to suppress for zksolc, possible values: [sendtransfer]" + )] + #[serde(skip_serializing_if = "Option::is_none")] + pub suppressed_errors: Option>, } impl ZkSyncArgs { @@ -157,6 +178,14 @@ impl ZkSyncArgs { self.optimizer_mode.as_ref().and_then(|mode| mode.parse::().ok()), zksync.optimizer_mode ); + let suppressed_warnings = self + .suppressed_warnings + .clone() + .map(|values| values.into_iter().collect::>()); + set_if_some!(suppressed_warnings, zksync.suppressed_warnings); + let suppressed_errors = + self.suppressed_errors.clone().map(|values| values.into_iter().collect::>()); + set_if_some!(suppressed_errors, zksync.suppressed_errors); zksync } diff --git a/crates/cli/src/opts/dependency.rs b/crates/cli/src/opts/dependency.rs index 6fa33a53f..6783e32d2 100644 --- a/crates/cli/src/opts/dependency.rs +++ b/crates/cli/src/opts/dependency.rs @@ -12,6 +12,9 @@ pub static GH_REPO_PREFIX_REGEX: LazyLock = LazyLock::new(|| { .unwrap() }); +static VERSION_PREFIX_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r#"@(tag|branch|rev)="#).unwrap()); + const GITHUB: &str = "github.com"; const VERSION_SEPARATOR: char = '@'; const ALIAS_SEPARATOR: char = '='; @@ -49,6 +52,12 @@ pub struct Dependency { impl FromStr for Dependency { type Err = eyre::Error; fn from_str(dependency: &str) -> Result { + // Handle dependency exact ref type (`@tag=`, `@branch=` or `@rev=`)`. + // Only extract version for first tag/branch/commit specified. + let url_and_version: Vec<&str> = VERSION_PREFIX_REGEX.split(dependency).collect(); + let dependency = url_and_version[0]; + let mut tag_or_branch = url_and_version.get(1).map(|version| version.to_string()); + // everything before "=" should be considered the alias let (mut alias, dependency) = if let Some(split) = dependency.split_once(ALIAS_SEPARATOR) { (Some(String::from(split.0)), split.1.to_string()) @@ -96,14 +105,15 @@ impl FromStr for Dependency { // `tag` does not contain a slash let mut split = url_with_version.rsplit(VERSION_SEPARATOR); - let mut tag = None; let mut url = url_with_version.as_str(); - let maybe_tag = split.next().unwrap(); - if let Some(actual_url) = split.next() { - if !maybe_tag.contains('/') { - tag = Some(maybe_tag.to_string()); - url = actual_url; + if tag_or_branch.is_none() { + let maybe_tag_or_branch = split.next().unwrap(); + if let Some(actual_url) = split.next() { + if !maybe_tag_or_branch.contains('/') { + tag_or_branch = Some(maybe_tag_or_branch.to_string()); + url = actual_url; + } } } @@ -114,7 +124,7 @@ impl FromStr for Dependency { .ok_or_else(|| eyre::eyre!("no dependency name found"))? .to_string(); - (Some(url), Some(name), tag) + (Some(url), Some(name), tag_or_branch) } else { (None, None, None) }; @@ -360,4 +370,26 @@ mod tests { let dep: Dependency = "org-git12345678@github.com:my-org/my-repo.git".parse().unwrap(); assert_eq!(dep.url.unwrap(), "https://github.com/my-org/my-repo"); } + + #[test] + fn can_parse_with_explicit_ref_type() { + let dep = Dependency::from_str("smartcontractkit/ccip@tag=contracts-ccip/v1.2.1").unwrap(); + assert_eq!(dep.name, "ccip"); + assert_eq!(dep.url, Some("https://github.com/smartcontractkit/ccip".to_string())); + assert_eq!(dep.tag, Some("contracts-ccip/v1.2.1".to_string())); + assert_eq!(dep.alias, None); + + let dep = + Dependency::from_str("smartcontractkit/ccip@branch=contracts-ccip/v1.2.1").unwrap(); + assert_eq!(dep.name, "ccip"); + assert_eq!(dep.url, Some("https://github.com/smartcontractkit/ccip".to_string())); + assert_eq!(dep.tag, Some("contracts-ccip/v1.2.1".to_string())); + assert_eq!(dep.alias, None); + + let dep = Dependency::from_str("smartcontractkit/ccip@rev=80eb41b").unwrap(); + assert_eq!(dep.name, "ccip"); + assert_eq!(dep.url, Some("https://github.com/smartcontractkit/ccip".to_string())); + assert_eq!(dep.tag, Some("80eb41b".to_string())); + assert_eq!(dep.alias, None); + } } diff --git a/crates/cli/src/opts/ethereum.rs b/crates/cli/src/opts/ethereum.rs index c4e8f0887..b858d998f 100644 --- a/crates/cli/src/opts/ethereum.rs +++ b/crates/cli/src/opts/ethereum.rs @@ -40,6 +40,14 @@ pub struct RpcOpts { /// "0x6bb38c26db65749ab6e472080a3d20a2f35776494e72016d1e339593f21c59bc"]' #[arg(long, env = "ETH_RPC_JWT_SECRET")] pub jwt_secret: Option, + + /// Timeout for the RPC request in seconds. + /// + /// The specified timeout will be used to override the default timeout for RPC requests. + /// + /// Default value: 45 + #[arg(long, env = "ETH_RPC_TIMEOUT")] + pub rpc_timeout: Option, } impl_figment_convert_cast!(RpcOpts); @@ -84,6 +92,9 @@ impl RpcOpts { if let Ok(Some(jwt)) = self.jwt(None) { dict.insert("eth_rpc_jwt".into(), jwt.into_owned().into()); } + if let Some(rpc_timeout) = self.rpc_timeout { + dict.insert("eth_rpc_timeout".into(), rpc_timeout.into()); + } dict } } diff --git a/crates/cli/src/opts/mod.rs b/crates/cli/src/opts/mod.rs index 7825cba3c..95bf9e126 100644 --- a/crates/cli/src/opts/mod.rs +++ b/crates/cli/src/opts/mod.rs @@ -2,10 +2,12 @@ mod build; mod chain; mod dependency; mod ethereum; +mod shell; mod transaction; pub use build::*; pub use chain::*; pub use dependency::*; pub use ethereum::*; +pub use shell::*; pub use transaction::*; diff --git a/crates/cli/src/opts/shell.rs b/crates/cli/src/opts/shell.rs new file mode 100644 index 000000000..fd83b952b --- /dev/null +++ b/crates/cli/src/opts/shell.rs @@ -0,0 +1,55 @@ +use clap::Parser; +use foundry_common::shell::{ColorChoice, OutputFormat, Shell, Verbosity}; + +// note: `verbose` and `quiet` cannot have `short` because of conflicts with multiple commands. + +/// Global shell options. +#[derive(Clone, Copy, Debug, Parser)] +pub struct ShellOpts { + /// Use verbose output. + #[clap(long, global = true, conflicts_with = "quiet", help_heading = "Display options")] + pub verbose: bool, + + /// Do not print log messages. + #[clap( + short, + long, + global = true, + alias = "silent", + conflicts_with = "verbose", + help_heading = "Display options" + )] + pub quiet: bool, + + /// Format log messages as JSON. + #[clap( + long, + global = true, + alias = "format-json", + conflicts_with_all = &["quiet", "color"], + help_heading = "Display options" + )] + pub json: bool, + + /// Log messages coloring. + #[clap(long, global = true, value_enum, help_heading = "Display options")] + pub color: Option, +} + +impl ShellOpts { + pub fn shell(self) -> Shell { + let verbosity = match (self.verbose, self.quiet) { + (true, false) => Verbosity::Verbose, + (false, true) => Verbosity::Quiet, + (false, false) => Verbosity::Normal, + (true, true) => unreachable!(), + }; + let color = self.json.then_some(ColorChoice::Never).or(self.color).unwrap_or_default(); + let format = match self.json { + true => OutputFormat::Json, + false => OutputFormat::Text, + }; + + Shell::new_with(format, color, verbosity) + } +} diff --git a/crates/cli/src/opts/transaction.rs b/crates/cli/src/opts/transaction.rs index 6730902f9..c0e229c35 100644 --- a/crates/cli/src/opts/transaction.rs +++ b/crates/cli/src/opts/transaction.rs @@ -1,9 +1,36 @@ -use crate::utils::parse_ether_value; -use alloy_primitives::{U256, U64}; +use std::str::FromStr; + +use crate::utils::{parse_ether_value, parse_json}; +use alloy_eips::{eip2930::AccessList, eip7702::SignedAuthorization}; +use alloy_primitives::{hex, Address, U256, U64}; +use alloy_rlp::Decodable; use clap::Parser; -use serde::Serialize; -#[derive(Clone, Debug, Serialize, Parser)] +/// CLI helper to parse a EIP-7702 authorization list. +/// Can be either a hex-encoded signed authorization or an address. +#[derive(Clone, Debug)] +pub enum CliAuthorizationList { + /// If an address is provided, we sign the authorization delegating to provided address. + Address(Address), + /// If RLP-encoded authorization is provided, we decode it and attach to transaction. + Signed(SignedAuthorization), +} + +impl FromStr for CliAuthorizationList { + type Err = eyre::Error; + + fn from_str(s: &str) -> Result { + if let Ok(addr) = Address::from_str(s) { + Ok(Self::Address(addr)) + } else if let Ok(auth) = SignedAuthorization::decode(&mut hex::decode(s)?.as_ref()) { + Ok(Self::Signed(auth)) + } else { + eyre::bail!("Failed to decode authorization") + } + } +} + +#[derive(Clone, Debug, Parser)] #[command(next_help_heading = "Transaction options")] pub struct TransactionOpts { /// Gas limit for the transaction. @@ -61,15 +88,15 @@ pub struct TransactionOpts { /// /// Can be either a hex-encoded signed authorization or an address. #[arg(long, conflicts_with_all = &["legacy", "blob"])] - pub auth: Option, + pub auth: Option, /// EIP-2930 access list. /// /// Accepts either a JSON-encoded access list or an empty value to create the access list /// via an RPC call to `eth_createAccessList`. To retrieve only the access list portion, use /// the `cast access-list` command. - #[arg(long)] - pub access_list: Option>, + #[arg(long, value_parser = parse_json::)] + pub access_list: Option>, } #[cfg(test)] diff --git a/crates/cli/src/utils/cmd.rs b/crates/cli/src/utils/cmd.rs index 07f661ef3..1bbfaf581 100644 --- a/crates/cli/src/utils/cmd.rs +++ b/crates/cli/src/utils/cmd.rs @@ -1,7 +1,7 @@ use alloy_json_abi::JsonAbi; use alloy_primitives::Address; use eyre::{Result, WrapErr}; -use foundry_common::{cli_warn, fs, TestFunctionExt}; +use foundry_common::{fs, TestFunctionExt}; use foundry_compilers::{ artifacts::{CompactBytecode, CompactDeployedBytecode, Settings}, cache::{CacheEntry, CompilerCache}, @@ -201,6 +201,8 @@ pub fn has_different_gas_calc(chain_id: u64) -> bool { NamedChain::ArbitrumGoerli | NamedChain::ArbitrumSepolia | NamedChain::ArbitrumTestnet | + NamedChain::Etherlink | + NamedChain::EtherlinkTestnet | NamedChain::Karura | NamedChain::KaruraTestnet | NamedChain::Mantle | @@ -307,35 +309,41 @@ where fn load_config_emit_warnings(self) -> Config { let config = self.load_config(); - config.warnings.iter().for_each(|w| cli_warn!("{w}")); + config.warnings.iter().for_each(|w| sh_warn!("{w}").unwrap()); config } fn try_load_config_emit_warnings(self) -> Result { let config = self.try_load_config()?; - config.warnings.iter().for_each(|w| cli_warn!("{w}")); + emit_warnings(&config); Ok(config) } fn load_config_and_evm_opts_emit_warnings(self) -> Result<(Config, EvmOpts)> { let (config, evm_opts) = self.load_config_and_evm_opts()?; - config.warnings.iter().for_each(|w| cli_warn!("{w}")); + emit_warnings(&config); Ok((config, evm_opts)) } fn load_config_unsanitized_emit_warnings(self) -> Config { let config = self.load_config_unsanitized(); - config.warnings.iter().for_each(|w| cli_warn!("{w}")); + emit_warnings(&config); config } fn try_load_config_unsanitized_emit_warnings(self) -> Result { let config = self.try_load_config_unsanitized()?; - config.warnings.iter().for_each(|w| cli_warn!("{w}")); + emit_warnings(&config); Ok(config) } } +fn emit_warnings(config: &Config) { + for warning in &config.warnings { + let _ = sh_warn!("{warning}"); + } +} + /// Read contract constructor arguments from the given file. pub fn read_constructor_args_file(constructor_args_path: PathBuf) -> Result> { if !constructor_args_path.exists() { @@ -386,6 +394,23 @@ impl TryFrom> for TraceResult { } } +impl From for TraceResult { + fn from(result: RawCallResult) -> Self { + Self::from_raw(result, TraceKind::Execution) + } +} + +impl TryFrom> for TraceResult { + type Error = EvmError; + + fn try_from(value: Result) -> Result { + match value { + Ok(result) => Ok(Self::from(result)), + Err(err) => Err(EvmError::from(err)), + } + } +} + /// labels the traces, conditionally prints them or opens the debugger pub async fn handle_traces( mut result: TraceResult, @@ -442,7 +467,7 @@ pub async fn handle_traces( .decoder(&decoder) .sources(sources) .build(); - debugger.try_run()?; + debugger.try_run_tui()?; } else { print_traces(&mut result, &decoder, verbose).await?; } diff --git a/crates/cli/src/utils/mod.rs b/crates/cli/src/utils/mod.rs index af3c5e0a5..2d8471e62 100644 --- a/crates/cli/src/utils/mod.rs +++ b/crates/cli/src/utils/mod.rs @@ -3,8 +3,12 @@ use alloy_primitives::U256; use alloy_provider::{network::AnyNetwork, Provider}; use alloy_transport::Transport; use eyre::{ContextCompat, Result}; -use foundry_common::provider::{ProviderBuilder, RetryProvider}; +use foundry_common::{ + provider::{ProviderBuilder, RetryProvider}, + shell, +}; use foundry_config::{Chain, Config}; +use serde::de::DeserializeOwned; use std::{ ffi::OsStr, future::Future, @@ -102,6 +106,10 @@ pub fn get_provider_builder(config: &Config) -> Result { builder = builder.jwt(jwt.as_ref()); } + if let Some(rpc_timeout) = config.eth_rpc_timeout { + builder = builder.timeout(Duration::from_secs(rpc_timeout)); + } + Ok(builder) } @@ -133,6 +141,11 @@ pub fn parse_ether_value(value: &str) -> Result { }) } +/// Parses a `T` from a string using [`serde_json::from_str`]. +pub fn parse_json(value: &str) -> serde_json::Result { + serde_json::from_str(value) +} + /// Parses a `Duration` from a &str pub fn parse_delay(delay: &str) -> Result { let delay = if delay.ends_with("ms") { @@ -161,23 +174,6 @@ pub fn block_on(future: F) -> F::Output { rt.block_on(future) } -/// Conditionally print a message -/// -/// This macro accepts a predicate and the message to print if the predicate is true -/// -/// ```ignore -/// let quiet = true; -/// p_println!(!quiet => "message"); -/// ``` -#[macro_export] -macro_rules! p_println { - ($p:expr => $($arg:tt)*) => {{ - if $p { - println!($($arg)*) - } - }} -} - /// Loads a dotenv file, from the cwd and the project root, ignoring potential failure. /// /// We could use `warn!` here, but that would imply that the dotenv file can't configure @@ -282,7 +278,7 @@ pub struct Git<'a> { impl<'a> Git<'a> { #[inline] pub fn new(root: &'a Path) -> Self { - Self { root, quiet: false, shallow: false } + Self { root, quiet: shell::is_quiet(), shallow: false } } #[inline] diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 5bb6a2024..bbc7c9721 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -65,6 +65,10 @@ url.workspace = true walkdir.workspace = true yansi.workspace = true +anstream.workspace = true +anstyle.workspace = true +terminal_size.workspace = true + # zksync globset = "0.4" diff --git a/crates/common/fmt/Cargo.toml b/crates/common/fmt/Cargo.toml index fabe35a7a..2a56b3b10 100644 --- a/crates/common/fmt/Cargo.toml +++ b/crates/common/fmt/Cargo.toml @@ -16,10 +16,10 @@ workspace = true [dependencies] alloy-primitives.workspace = true alloy-dyn-abi = { workspace = true, features = ["eip712"] } -yansi.workspace = true # ui alloy-consensus.workspace = true +alloy-network.workspace = true alloy-rpc-types = { workspace = true, features = ["eth"] } alloy-serde.workspace = true serde.workspace = true @@ -27,6 +27,7 @@ serde_json.workspace = true chrono.workspace = true revm-primitives.workspace = true comfy-table.workspace = true +yansi.workspace = true [dev-dependencies] foundry-macros.workspace = true diff --git a/crates/common/fmt/src/ui.rs b/crates/common/fmt/src/ui.rs index a82853145..5534e72d8 100644 --- a/crates/common/fmt/src/ui.rs +++ b/crates/common/fmt/src/ui.rs @@ -1,9 +1,10 @@ //! Helper trait and functions to format Ethereum types. use alloy_consensus::{AnyReceiptEnvelope, Eip658Value, Receipt, ReceiptWithBloom, TxType}; +use alloy_network::ReceiptResponse; use alloy_primitives::{hex, Address, Bloom, Bytes, FixedBytes, Uint, B256, I256, U256, U64}; use alloy_rpc_types::{ - AccessListItem, AnyNetworkBlock, AnyTransactionReceipt, Block, BlockTransactions, Log, + AccessListItem, AnyNetworkBlock, AnyTransactionReceipt, Block, BlockTransactions, Header, Log, Transaction, TransactionReceipt, }; use alloy_serde::{OtherFields, WithOtherFields}; @@ -169,7 +170,6 @@ impl UIfmt for AnyTransactionReceipt { to, gas_used, contract_address, - state_root, effective_gas_price, inner: AnyReceiptEnvelope { @@ -215,7 +215,7 @@ authorizationList {}", gas_used.pretty(), serde_json::to_string(&logs).unwrap(), logs_bloom.pretty(), - state_root.pretty(), + self.state_root().pretty(), status.pretty(), transaction_hash.pretty(), transaction_index.pretty(), @@ -597,6 +597,9 @@ pub fn get_pretty_block_attr(block: &AnyNetworkBlock, attr: &str) -> Option Some(block.header.state_root.pretty()), "timestamp" => Some(block.header.timestamp.pretty()), "totalDifficulty" | "total_difficult" => Some(block.header.total_difficulty.pretty()), + "blobGasUsed" | "blob_gas_used" => Some(block.header.blob_gas_used.pretty()), + "excessBlobGas" | "excess_blob_gas" => Some(block.header.excess_blob_gas.pretty()), + "requestsHash" | "requests_hash" => Some(block.header.requests_hash.pretty()), other => { if let Some(value) = block.other.get(other) { let val = EthValue::from(value.clone()); @@ -608,6 +611,38 @@ pub fn get_pretty_block_attr(block: &AnyNetworkBlock, attr: &str) -> Option(block: &Block) -> String { + let Block { + header: + Header { + hash, + parent_hash, + uncles_hash, + miner, + state_root, + transactions_root, + receipts_root, + logs_bloom, + difficulty, + number, + gas_limit, + gas_used, + timestamp, + total_difficulty, + extra_data, + mix_hash, + nonce, + base_fee_per_gas, + withdrawals_root, + blob_gas_used, + excess_blob_gas, + parent_beacon_block_root, + requests_hash, + }, + uncles: _, + transactions: _, + size, + withdrawals: _, + } = block; format!( " baseFeePerGas {} @@ -630,31 +665,37 @@ size {} stateRoot {} timestamp {} ({}) withdrawalsRoot {} -totalDifficulty {}", - block.header.base_fee_per_gas.pretty(), - block.header.difficulty.pretty(), - block.header.extra_data.pretty(), - block.header.gas_limit.pretty(), - block.header.gas_used.pretty(), - block.header.hash.pretty(), - block.header.logs_bloom.pretty(), - block.header.miner.pretty(), - block.header.mix_hash.pretty(), - block.header.nonce.pretty(), - block.header.number.pretty(), - block.header.parent_hash.pretty(), - block.header.parent_beacon_block_root.pretty(), - block.header.transactions_root.pretty(), - block.header.receipts_root.pretty(), - block.header.uncles_hash.pretty(), - block.size.pretty(), - block.header.state_root.pretty(), - block.header.timestamp.pretty(), - chrono::DateTime::from_timestamp(block.header.timestamp as i64, 0) +totalDifficulty {} +blobGasUsed {} +excessBlobGas {} +requestsHash {}", + base_fee_per_gas.pretty(), + difficulty.pretty(), + extra_data.pretty(), + gas_limit.pretty(), + gas_used.pretty(), + hash.pretty(), + logs_bloom.pretty(), + miner.pretty(), + mix_hash.pretty(), + nonce.pretty(), + number.pretty(), + parent_hash.pretty(), + parent_beacon_block_root.pretty(), + transactions_root.pretty(), + receipts_root.pretty(), + uncles_hash.pretty(), + size.pretty(), + state_root.pretty(), + timestamp.pretty(), + chrono::DateTime::from_timestamp(*timestamp as i64, 0) .expect("block timestamp in range") .to_rfc2822(), - block.header.withdrawals_root.pretty(), - block.header.total_difficulty.pretty(), + withdrawals_root.pretty(), + total_difficulty.pretty(), + blob_gas_used.pretty(), + excess_blob_gas.pretty(), + requests_hash.pretty(), ) } diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index 1495c445a..d1786fc8f 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -50,6 +50,9 @@ pub struct ProjectCompiler { /// Whether to bail on compiler errors. bail: Option, + /// Whether to ignore the contract initcode size limit introduced by EIP-3860. + ignore_eip_3860: bool, + /// Extra files to include, that are not necessarily in the project's source dir. files: Vec, @@ -72,8 +75,9 @@ impl ProjectCompiler { verify: None, print_names: None, print_sizes: None, - quiet: Some(crate::shell::verbosity().is_silent()), + quiet: Some(crate::shell::is_quiet()), bail: None, + ignore_eip_3860: false, files: Vec::new(), zksync: false, } @@ -108,19 +112,17 @@ impl ProjectCompiler { self } - /// Do not print anything at all if true. Overrides other `print` options. + /// Sets whether to bail on compiler errors. #[inline] - pub fn quiet_if(mut self, maybe: bool) -> Self { - if maybe { - self.quiet = Some(true); - } + pub fn bail(mut self, yes: bool) -> Self { + self.bail = Some(yes); self } - /// Sets whether to bail on compiler errors. + /// Sets whether to ignore EIP-3860 initcode size limits. #[inline] - pub fn bail(mut self, yes: bool) -> Self { - self.bail = Some(yes); + pub fn ignore_eip_3860(mut self, yes: bool) -> Self { + self.ignore_eip_3860 = yes; self } @@ -249,7 +251,8 @@ impl ProjectCompiler { .collect(); for (name, artifact) in artifacts { - let size = deployed_contract_size(artifact).unwrap_or_default(); + let runtime_size = contract_size(artifact, false).unwrap_or_default(); + let init_size = contract_size(artifact, true).unwrap_or_default(); let dev_functions = artifact.abi.as_ref().map(|abi| abi.functions()).into_iter().flatten().filter( @@ -261,14 +264,21 @@ impl ProjectCompiler { ); let is_dev_contract = dev_functions.count() > 0; - size_report.contracts.insert(name, ContractInfo { size, is_dev_contract }); + size_report + .contracts + .insert(name, ContractInfo { runtime_size, init_size, is_dev_contract }); } println!("{size_report}"); // TODO: avoid process::exit // exit with error if any contract exceeds the size limit, excluding test contracts. - if size_report.exceeds_size_limit() { + if size_report.exceeds_runtime_size_limit() { + std::process::exit(1); + } + + // Check size limits only if not ignoring EIP-3860 + if !self.ignore_eip_3860 && size_report.exceeds_initcode_size_limit() { std::process::exit(1); } } @@ -472,14 +482,8 @@ impl ProjectCompiler { .collect(); for (name, artifact) in artifacts { - let bytecode = artifact.get_bytecode_object().unwrap_or_default(); - let size = match bytecode.as_ref() { - BytecodeObject::Bytecode(bytes) => bytes.len(), - BytecodeObject::Unlinked(_) => { - // TODO: This should never happen on zksolc, maybe error somehow - 0 - } - }; + let runtime_size = contract_size(artifact, false).unwrap_or_default(); + let init_size = contract_size(artifact, true).unwrap_or_default(); let is_dev_contract = artifact .abi @@ -491,14 +495,21 @@ impl ProjectCompiler { }) }) .unwrap_or(false); - size_report.contracts.insert(name, ContractInfo { size, is_dev_contract }); + size_report + .contracts + .insert(name, ContractInfo { runtime_size, init_size, is_dev_contract }); } println!("{size_report}"); // TODO: avoid process::exit // exit with error if any contract exceeds the size limit, excluding test contracts. - if size_report.exceeds_size_limit() { + if size_report.exceeds_runtime_size_limit() { + std::process::exit(1); + } + + // Check size limits only if not ignoring EIP-3860 + if !self.ignore_eip_3860 && size_report.exceeds_initcode_size_limit() { std::process::exit(1); } } @@ -507,7 +518,10 @@ impl ProjectCompiler { } // https://eips.ethereum.org/EIPS/eip-170 -const CONTRACT_SIZE_LIMIT: usize = 24576; +const CONTRACT_RUNTIME_SIZE_LIMIT: usize = 24576; + +// https://eips.ethereum.org/EIPS/eip-3860 +const CONTRACT_INITCODE_SIZE_LIMIT: usize = 49152; // https://docs.zksync.io/build/developer-reference/ethereum-differences/contract-deployment#contract-size-limit-and-format-of-bytecode-hash const ZKSYNC_CONTRACT_SIZE_LIMIT: usize = 450999; @@ -521,23 +535,41 @@ pub struct SizeReport { } impl SizeReport { - /// Returns the size of the largest contract, excluding test contracts. - pub fn max_size(&self) -> usize { - let mut max_size = 0; - for contract in self.contracts.values() { - if !contract.is_dev_contract && contract.size > max_size { - max_size = contract.size; - } + /// Returns the maximum runtime code size, excluding dev contracts. + pub fn max_runtime_size(&self) -> usize { + self.contracts + .values() + .filter(|c| !c.is_dev_contract) + .map(|c| c.runtime_size) + .max() + .unwrap_or(0) + } + + /// Returns the maximum initcode size, excluding dev contracts. + pub fn max_init_size(&self) -> usize { + self.contracts + .values() + .filter(|c| !c.is_dev_contract) + .map(|c| c.init_size) + .max() + .unwrap_or(0) + } + + /// Returns true if any contract exceeds the runtime size limit, excluding dev contracts. + pub fn exceeds_runtime_size_limit(&self) -> bool { + if self.zksync { + self.max_runtime_size() > ZKSYNC_CONTRACT_SIZE_LIMIT + } else { + self.max_runtime_size() > CONTRACT_RUNTIME_SIZE_LIMIT } - max_size } - /// Returns true if any contract exceeds the size limit, excluding test contracts. - pub fn exceeds_size_limit(&self) -> bool { + /// Returns true if any contract exceeds the initcode size limit, excluding dev contracts. + pub fn exceeds_initcode_size_limit(&self) -> bool { if self.zksync { - self.max_size() > ZKSYNC_CONTRACT_SIZE_LIMIT + self.max_init_size() > ZKSYNC_CONTRACT_SIZE_LIMIT } else { - self.max_size() > CONTRACT_SIZE_LIMIT + self.max_init_size() > CONTRACT_INITCODE_SIZE_LIMIT } } } @@ -548,40 +580,72 @@ impl Display for SizeReport { table.load_preset(ASCII_MARKDOWN); table.set_header([ Cell::new("Contract").add_attribute(Attribute::Bold).fg(Color::Blue), - Cell::new("Size (B)").add_attribute(Attribute::Bold).fg(Color::Blue), - Cell::new("Margin (B)").add_attribute(Attribute::Bold).fg(Color::Blue), + Cell::new("Runtime Size (B)").add_attribute(Attribute::Bold).fg(Color::Blue), + Cell::new("Initcode Size (B)").add_attribute(Attribute::Bold).fg(Color::Blue), + Cell::new("Runtime Margin (B)").add_attribute(Attribute::Bold).fg(Color::Blue), + Cell::new("Initcode Margin (B)").add_attribute(Attribute::Bold).fg(Color::Blue), ]); - // filters out non dev contracts (Test or Script) - let contracts = self.contracts.iter().filter(|(_, c)| !c.is_dev_contract && c.size > 0); + // Filters out dev contracts (Test or Script) + let contracts = self + .contracts + .iter() + .filter(|(_, c)| !c.is_dev_contract && (c.runtime_size > 0 || c.init_size > 0)); for (name, contract) in contracts { - let (margin, color) = if self.zksync { - let margin = ZKSYNC_CONTRACT_SIZE_LIMIT as isize - contract.size as isize; - let color = match contract.size { + let ((runtime_margin, runtime_color), (init_margin, init_color)) = if self.zksync { + let runtime_margin = + ZKSYNC_CONTRACT_SIZE_LIMIT as isize - contract.runtime_size as isize; + let init_margin = ZKSYNC_CONTRACT_SIZE_LIMIT as isize - contract.init_size as isize; + + let runtime_color = match contract.runtime_size { + 0..=329999 => Color::Reset, + 330000..=ZKSYNC_CONTRACT_SIZE_LIMIT => Color::Yellow, + _ => Color::Red, + }; + + let init_color = match contract.init_size { 0..=329999 => Color::Reset, 330000..=ZKSYNC_CONTRACT_SIZE_LIMIT => Color::Yellow, _ => Color::Red, }; - (margin, color) + + ((runtime_margin, runtime_color), (init_margin, init_color)) } else { - let margin = CONTRACT_SIZE_LIMIT as isize - contract.size as isize; - let color = match contract.size { - 0..=17999 => Color::Reset, - 18000..=CONTRACT_SIZE_LIMIT => Color::Yellow, + let runtime_margin = + CONTRACT_RUNTIME_SIZE_LIMIT as isize - contract.runtime_size as isize; + let init_margin = + CONTRACT_INITCODE_SIZE_LIMIT as isize - contract.init_size as isize; + + let runtime_color = match contract.runtime_size { + ..18_000 => Color::Reset, + 18_000..=CONTRACT_RUNTIME_SIZE_LIMIT => Color::Yellow, _ => Color::Red, }; - (margin, color) + + let init_color = match contract.init_size { + ..36_000 => Color::Reset, + 36_000..=CONTRACT_INITCODE_SIZE_LIMIT => Color::Yellow, + _ => Color::Red, + }; + + ((runtime_margin, runtime_color), (init_margin, init_color)) }; let locale = &Locale::en; table.add_row([ - Cell::new(name).fg(color), - Cell::new(contract.size.to_formatted_string(locale)) + Cell::new(name).fg(Color::Blue), + Cell::new(contract.runtime_size.to_formatted_string(locale)) + .set_alignment(CellAlignment::Right) + .fg(runtime_color), + Cell::new(contract.init_size.to_formatted_string(locale)) .set_alignment(CellAlignment::Right) - .fg(color), - Cell::new(margin.to_formatted_string(locale)) + .fg(init_color), + Cell::new(runtime_margin.to_formatted_string(locale)) .set_alignment(CellAlignment::Right) - .fg(color), + .fg(runtime_color), + Cell::new(init_margin.to_formatted_string(locale)) + .set_alignment(CellAlignment::Right) + .fg(init_color), ]); } @@ -590,9 +654,14 @@ impl Display for SizeReport { } } -/// Returns the size of the deployed contract -pub fn deployed_contract_size(artifact: &T) -> Option { - let bytecode = artifact.get_deployed_bytecode_object()?; +/// Returns the deployed or init size of the contract. +fn contract_size(artifact: &T, initcode: bool) -> Option { + let bytecode = if initcode { + artifact.get_bytecode_object()? + } else { + artifact.get_deployed_bytecode_object()? + }; + let size = match bytecode.as_ref() { BytecodeObject::Bytecode(bytes) => bytes.len(), BytecodeObject::Unlinked(unlinked) => { @@ -606,14 +675,17 @@ pub fn deployed_contract_size(artifact: &T) -> Option { size / 2 } }; + Some(size) } /// How big the contract is and whether it is a dev contract where size limits can be neglected #[derive(Clone, Copy, Debug)] pub struct ContractInfo { - /// size of the contract in bytes - pub size: usize, + /// Size of the runtime code in bytes + pub runtime_size: usize, + /// Size of the initcode in bytes + pub init_size: usize, /// A development contract is either a Script or a Test contract. pub is_dev_contract: bool, } diff --git a/crates/common/src/io/macros.rs b/crates/common/src/io/macros.rs new file mode 100644 index 000000000..10e7cca4a --- /dev/null +++ b/crates/common/src/io/macros.rs @@ -0,0 +1,198 @@ +/// Prints a message to [`stdout`][std::io::stdout] and reads a line from stdin into a String. +/// +/// Returns `Result`, so sometimes `T` must be explicitly specified, like in `str::parse`. +/// +/// # Examples +/// +/// ```no_run +/// use foundry_common::prompt; +/// +/// let response: String = prompt!("Would you like to continue? [y/N] ")?; +/// if !matches!(response.as_str(), "y" | "Y") { +/// return Ok(()) +/// } +/// # Ok::<(), Box>(()) +/// ``` +#[macro_export] +macro_rules! prompt { + () => { + $crate::stdin::parse_line() + }; + + ($($tt:tt)+) => {{ + let _ = $crate::sh_print!($($tt)+); + match ::std::io::Write::flush(&mut ::std::io::stdout()) { + ::core::result::Result::Ok(()) => $crate::prompt!(), + ::core::result::Result::Err(e) => ::core::result::Result::Err(::eyre::eyre!("Could not flush stdout: {e}")) + } + }}; +} + +/// Prints a formatted error to stderr. +/// +/// **Note**: will log regardless of the verbosity level. +#[macro_export] +macro_rules! sh_err { + ($($args:tt)*) => { + $crate::__sh_dispatch!(error $($args)*) + }; +} + +/// Prints a formatted warning to stderr. +/// +/// **Note**: if `verbosity` is set to `Quiet`, this is a no-op. +#[macro_export] +macro_rules! sh_warn { + ($($args:tt)*) => { + $crate::__sh_dispatch!(warn $($args)*) + }; +} + +/// Prints a raw formatted message to stdout. +/// +/// **Note**: if `verbosity` is set to `Quiet`, this is a no-op. +#[macro_export] +macro_rules! sh_print { + ($($args:tt)*) => { + $crate::__sh_dispatch!(print_out $($args)*) + }; + + ($shell:expr, $($args:tt)*) => { + $crate::__sh_dispatch!(print_out $shell, $($args)*) + }; +} + +/// Prints a raw formatted message to stderr. +/// +/// **Note**: if `verbosity` is set to `Quiet`, this is a no-op. +#[macro_export] +macro_rules! sh_eprint { + ($($args:tt)*) => { + $crate::__sh_dispatch!(print_err $($args)*) + }; + + ($shell:expr, $($args:tt)*) => { + $crate::__sh_dispatch!(print_err $shell, $($args)*) + }; +} + +/// Prints a raw formatted message to stdout, with a trailing newline. +/// +/// **Note**: if `verbosity` is set to `Quiet`, this is a no-op. +#[macro_export] +macro_rules! sh_println { + () => { + $crate::sh_print!("\n") + }; + + ($fmt:literal $($args:tt)*) => { + $crate::sh_print!("{}\n", ::core::format_args!($fmt $($args)*)) + }; + + ($shell:expr $(,)?) => { + $crate::sh_print!($shell, "\n").expect("failed to write newline") + }; + + ($shell:expr, $($args:tt)*) => { + $crate::sh_print!($shell, "{}\n", ::core::format_args!($($args)*)) + }; + + ($($args:tt)*) => { + $crate::sh_print!("{}\n", ::core::format_args!($($args)*)) + }; +} + +/// Prints a raw formatted message to stderr, with a trailing newline. +/// +/// **Note**: if `verbosity` is set to `Quiet`, this is a no-op. +#[macro_export] +macro_rules! sh_eprintln { + () => { + $crate::sh_eprint!("\n") + }; + + ($fmt:literal $($args:tt)*) => { + $crate::sh_eprint!("{}\n", ::core::format_args!($fmt $($args)*)) + }; + + ($shell:expr $(,)?) => { + $crate::sh_eprint!($shell, "\n") + }; + + ($shell:expr, $($args:tt)*) => { + $crate::sh_eprint!($shell, "{}\n", ::core::format_args!($($args)*)) + }; + + ($($args:tt)*) => { + $crate::sh_eprint!("{}\n", ::core::format_args!($($args)*)) + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __sh_dispatch { + ($f:ident $fmt:literal $($args:tt)*) => { + $crate::__sh_dispatch!(@impl $f &mut *$crate::Shell::get(), $fmt $($args)*) + }; + + ($f:ident $shell:expr, $($args:tt)*) => { + $crate::__sh_dispatch!(@impl $f $shell, $($args)*) + }; + + ($f:ident $($args:tt)*) => { + $crate::__sh_dispatch!(@impl $f &mut *$crate::Shell::get(), $($args)*) + }; + + // Ensure that the global shell lock is held for as little time as possible. + // Also avoids deadlocks in case of nested calls. + (@impl $f:ident $shell:expr, $($args:tt)*) => { + match ::core::format_args!($($args)*) { + fmt => $crate::Shell::$f($shell, fmt), + } + }; +} + +#[cfg(test)] +mod tests { + #[test] + fn macros() -> eyre::Result<()> { + sh_err!("err")?; + sh_err!("err {}", "arg")?; + + sh_warn!("warn")?; + sh_warn!("warn {}", "arg")?; + + sh_print!("print -")?; + sh_print!("print {} -", "arg")?; + + sh_println!()?; + sh_println!("println")?; + sh_println!("println {}", "arg")?; + + sh_eprint!("eprint -")?; + sh_eprint!("eprint {} -", "arg")?; + + sh_eprintln!()?; + sh_eprintln!("eprintln")?; + sh_eprintln!("eprintln {}", "arg")?; + + sh_println!("{:?}", { + sh_println!("hi")?; + "nested" + })?; + + Ok(()) + } + + #[test] + fn macros_with_shell() -> eyre::Result<()> { + let shell = &mut crate::Shell::new(); + sh_eprintln!(shell)?; + sh_eprintln!(shell,)?; + sh_eprintln!(shell, "shelled eprintln")?; + sh_eprintln!(shell, "shelled eprintln {}", "arg")?; + sh_eprintln!(&mut crate::Shell::new(), "shelled eprintln {}", "arg")?; + + Ok(()) + } +} diff --git a/crates/common/src/io/mod.rs b/crates/common/src/io/mod.rs new file mode 100644 index 000000000..f62fd0346 --- /dev/null +++ b/crates/common/src/io/mod.rs @@ -0,0 +1,11 @@ +//! Utilities for working with standard input, output, and error. + +#[macro_use] +mod macros; + +pub mod shell; +pub mod stdin; +pub mod style; + +#[doc(no_inline)] +pub use shell::Shell; diff --git a/crates/common/src/io/shell.rs b/crates/common/src/io/shell.rs new file mode 100644 index 000000000..45d9c2296 --- /dev/null +++ b/crates/common/src/io/shell.rs @@ -0,0 +1,530 @@ +//! Utility functions for writing to [`stdout`](std::io::stdout) and [`stderr`](std::io::stderr). +//! +//! Originally from [cargo](https://github.com/rust-lang/cargo/blob/35814255a1dbaeca9219fae81d37a8190050092c/src/cargo/core/shell.rs). + +use super::style::*; +use anstream::AutoStream; +use anstyle::Style; +use clap::ValueEnum; +use eyre::Result; +use std::{ + fmt, + io::{prelude::*, IsTerminal}, + ops::DerefMut, + sync::{ + atomic::{AtomicBool, Ordering}, + Mutex, OnceLock, PoisonError, + }, +}; + +/// Returns the currently set verbosity. +pub fn verbosity() -> Verbosity { + Shell::get().verbosity() +} + +/// Returns whether the verbosity level is [`Verbosity::Quiet`]. +pub fn is_quiet() -> bool { + verbosity().is_quiet() +} + +/// Returns whether the output format is [`OutputFormat::Json`]. +pub fn is_json() -> bool { + Shell::get().output_format().is_json() +} + +/// The global shell instance. +static GLOBAL_SHELL: OnceLock> = OnceLock::new(); + +/// Terminal width. +pub enum TtyWidth { + /// Not a terminal, or could not determine size. + NoTty, + /// A known width. + Known(usize), + /// A guess at the width. + Guess(usize), +} + +impl TtyWidth { + /// Returns the width of the terminal from the environment, if known. + pub fn get() -> Self { + // use stderr + #[cfg(unix)] + let opt = terminal_size::terminal_size_of(std::io::stderr()); + #[cfg(not(unix))] + let opt = terminal_size::terminal_size(); + match opt { + Some((w, _)) => Self::Known(w.0 as usize), + None => Self::NoTty, + } + } + + /// Returns the width used by progress bars for the tty. + pub fn progress_max_width(&self) -> Option { + match *self { + Self::NoTty => None, + Self::Known(width) | Self::Guess(width) => Some(width), + } + } +} + +/// The requested verbosity of output. +#[derive(Debug, Default, Clone, Copy, PartialEq)] +pub enum Verbosity { + /// All output + Verbose, + /// Default output + #[default] + Normal, + /// No output + Quiet, +} + +impl Verbosity { + /// Returns true if the verbosity level is `Verbose`. + #[inline] + pub fn is_verbose(self) -> bool { + self == Self::Verbose + } + + /// Returns true if the verbosity level is `Normal`. + #[inline] + pub fn is_normal(self) -> bool { + self == Self::Normal + } + + /// Returns true if the verbosity level is `Quiet`. + #[inline] + pub fn is_quiet(self) -> bool { + self == Self::Quiet + } +} + +/// The requested output format. +#[derive(Debug, Default, Clone, Copy, PartialEq)] +pub enum OutputFormat { + /// Plain text output. + #[default] + Text, + /// JSON output. + Json, +} + +impl OutputFormat { + /// Returns true if the output format is `Text`. + #[inline] + pub fn is_text(self) -> bool { + self == Self::Text + } + + /// Returns true if the output format is `Json`. + #[inline] + pub fn is_json(self) -> bool { + self == Self::Json + } +} + +/// An abstraction around console output that remembers preferences for output +/// verbosity and color. +pub struct Shell { + /// Wrapper around stdout/stderr. This helps with supporting sending + /// output to a memory buffer which is useful for tests. + output: ShellOut, + + /// The format to use for message output. + output_format: OutputFormat, + + /// How verbose messages should be. + verbosity: Verbosity, + + /// Flag that indicates the current line needs to be cleared before + /// printing. Used when a progress bar is currently displayed. + needs_clear: AtomicBool, +} + +impl fmt::Debug for Shell { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut s = f.debug_struct("Shell"); + s.field("verbosity", &self.verbosity); + if let ShellOut::Stream { color_choice, .. } = self.output { + s.field("color_choice", &color_choice); + } + s.finish() + } +} + +/// A `Write`able object, either with or without color support. +enum ShellOut { + /// Color-enabled stdio, with information on whether color should be used. + Stream { + stdout: AutoStream, + stderr: AutoStream, + stderr_tty: bool, + color_choice: ColorChoice, + }, + /// A write object that ignores all output. + Empty(std::io::Empty), +} + +/// Whether messages should use color output. +#[derive(Debug, Default, PartialEq, Clone, Copy, ValueEnum)] +pub enum ColorChoice { + /// Intelligently guess whether to use color output (default). + #[default] + Auto, + /// Force color output. + Always, + /// Force disable color output. + Never, +} + +impl Default for Shell { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl Shell { + /// Creates a new shell (color choice and verbosity), defaulting to 'auto' color and verbose + /// output. + #[inline] + pub fn new() -> Self { + Self::new_with(OutputFormat::Text, ColorChoice::Auto, Verbosity::Verbose) + } + + /// Creates a new shell with the given color choice and verbosity. + #[inline] + pub fn new_with(format: OutputFormat, color: ColorChoice, verbosity: Verbosity) -> Self { + Self { + output: ShellOut::Stream { + stdout: AutoStream::new(std::io::stdout(), color.to_anstream_color_choice()), + stderr: AutoStream::new(std::io::stderr(), color.to_anstream_color_choice()), + color_choice: color, + stderr_tty: std::io::stderr().is_terminal(), + }, + output_format: format, + verbosity, + needs_clear: AtomicBool::new(false), + } + } + + /// Creates a shell that ignores all output. + #[inline] + pub fn empty() -> Self { + Self { + output: ShellOut::Empty(std::io::empty()), + output_format: OutputFormat::Text, + verbosity: Verbosity::Quiet, + needs_clear: AtomicBool::new(false), + } + } + + /// Acquire a lock to the global shell. + /// + /// Initializes it with the default values if it has not been set yet. + pub fn get() -> impl DerefMut + 'static { + GLOBAL_SHELL.get_or_init(Default::default).lock().unwrap_or_else(PoisonError::into_inner) + } + + /// Set the global shell. + /// + /// # Panics + /// + /// Panics if the global shell has already been set. + #[track_caller] + pub fn set(self) { + GLOBAL_SHELL + .set(Mutex::new(self)) + .unwrap_or_else(|_| panic!("attempted to set global shell twice")) + } + + /// Sets whether the next print should clear the current line and returns the previous value. + #[inline] + pub fn set_needs_clear(&self, needs_clear: bool) -> bool { + self.needs_clear.swap(needs_clear, Ordering::Relaxed) + } + + /// Returns `true` if the `needs_clear` flag is set. + #[inline] + pub fn needs_clear(&self) -> bool { + self.needs_clear.load(Ordering::Relaxed) + } + + /// Returns `true` if the `needs_clear` flag is unset. + #[inline] + pub fn is_cleared(&self) -> bool { + !self.needs_clear() + } + + /// Returns the width of the terminal in spaces, if any. + #[inline] + pub fn err_width(&self) -> TtyWidth { + match self.output { + ShellOut::Stream { stderr_tty: true, .. } => TtyWidth::get(), + _ => TtyWidth::NoTty, + } + } + + /// Gets the verbosity of the shell. + #[inline] + pub fn verbosity(&self) -> Verbosity { + self.verbosity + } + + /// Gets the output format of the shell. + pub fn output_format(&self) -> OutputFormat { + self.output_format + } + + /// Gets the current color choice. + /// + /// If we are not using a color stream, this will always return `Never`, even if the color + /// choice has been set to something else. + #[inline] + pub fn color_choice(&self) -> ColorChoice { + match self.output { + ShellOut::Stream { color_choice, .. } => color_choice, + ShellOut::Empty(_) => ColorChoice::Never, + } + } + + /// Returns `true` if stderr is a tty. + #[inline] + pub fn is_err_tty(&self) -> bool { + match self.output { + ShellOut::Stream { stderr_tty, .. } => stderr_tty, + ShellOut::Empty(_) => false, + } + } + + /// Whether `stderr` supports color. + #[inline] + pub fn err_supports_color(&self) -> bool { + match &self.output { + ShellOut::Stream { stderr, .. } => supports_color(stderr.current_choice()), + ShellOut::Empty(_) => false, + } + } + + /// Whether `stdout` supports color. + #[inline] + pub fn out_supports_color(&self) -> bool { + match &self.output { + ShellOut::Stream { stdout, .. } => supports_color(stdout.current_choice()), + ShellOut::Empty(_) => false, + } + } + + /// Gets a reference to the underlying stdout writer. + pub fn out(&mut self) -> &mut dyn Write { + self.maybe_err_erase_line(); + self.output.stdout() + } + + /// Gets a reference to the underlying stderr writer. + pub fn err(&mut self) -> &mut dyn Write { + self.maybe_err_erase_line(); + self.output.stderr() + } + + /// Erase from cursor to end of line if needed. + pub fn maybe_err_erase_line(&mut self) { + if self.err_supports_color() && self.set_needs_clear(false) { + // This is the "EL - Erase in Line" sequence. It clears from the cursor + // to the end of line. + // https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences + let _ = self.output.stderr().write_all(b"\x1B[K"); + } + } + + /// Runs the callback only if we are in verbose mode. + #[inline] + pub fn verbose(&mut self, mut callback: impl FnMut(&mut Self) -> Result<()>) -> Result<()> { + match self.verbosity { + Verbosity::Verbose => callback(self), + _ => Ok(()), + } + } + + /// Runs the callback if we are not in verbose mode. + #[inline] + pub fn concise(&mut self, mut callback: impl FnMut(&mut Self) -> Result<()>) -> Result<()> { + match self.verbosity { + Verbosity::Verbose => Ok(()), + _ => callback(self), + } + } + + /// Prints a red 'error' message. Use the [`sh_err!`] macro instead. + /// This will render a message in [ERROR] style with a bold `Error: ` prefix. + /// + /// **Note**: will log regardless of the verbosity level. + pub fn error(&mut self, message: impl fmt::Display) -> Result<()> { + self.maybe_err_erase_line(); + self.output.message_stderr(&"Error", &ERROR, Some(&message), false) + } + + /// Prints an amber 'warning' message. Use the [`sh_warn!`] macro instead. + /// This will render a message in [WARN] style with a bold `Warning: `prefix. + /// + /// **Note**: if `verbosity` is set to `Quiet`, this is a no-op. + pub fn warn(&mut self, message: impl fmt::Display) -> Result<()> { + match self.verbosity { + Verbosity::Quiet => Ok(()), + _ => self.print(&"Warning", &WARN, Some(&message), false), + } + } + + /// Write a styled fragment. + /// + /// Caller is responsible for deciding whether [`Shell::verbosity`] is affects output. + pub fn write_stdout(&mut self, fragment: impl fmt::Display, color: &Style) -> Result<()> { + self.output.write_stdout(fragment, color) + } + + /// Write a styled fragment with the default color. Use the [`sh_print!`] macro instead. + /// + /// **Note**: if `verbosity` is set to `Quiet`, this is a no-op. + pub fn print_out(&mut self, fragment: impl fmt::Display) -> Result<()> { + if self.verbosity == Verbosity::Quiet { + Ok(()) + } else { + self.write_stdout(fragment, &Style::new()) + } + } + + /// Write a styled fragment + /// + /// Caller is responsible for deciding whether [`Shell::verbosity`] is affects output. + pub fn write_stderr(&mut self, fragment: impl fmt::Display, color: &Style) -> Result<()> { + self.output.write_stderr(fragment, color) + } + + /// Write a styled fragment with the default color. Use the [`sh_eprint!`] macro instead. + /// + /// **Note**: if `verbosity` is set to `Quiet`, this is a no-op. + pub fn print_err(&mut self, fragment: impl fmt::Display) -> Result<()> { + if self.verbosity == Verbosity::Quiet { + Ok(()) + } else { + self.write_stderr(fragment, &Style::new()) + } + } + + /// Prints a message, where the status will have `color` color, and can be justified. The + /// messages follows without color. + fn print( + &mut self, + status: &dyn fmt::Display, + style: &Style, + message: Option<&dyn fmt::Display>, + justified: bool, + ) -> Result<()> { + match self.verbosity { + Verbosity::Quiet => Ok(()), + _ => { + self.maybe_err_erase_line(); + self.output.message_stderr(status, style, message, justified) + } + } + } +} + +impl ShellOut { + /// Prints out a message with a status to stderr. The status comes first, and is bold plus the + /// given color. The status can be justified, in which case the max width that will right + /// align is 12 chars. + fn message_stderr( + &mut self, + status: &dyn fmt::Display, + style: &Style, + message: Option<&dyn fmt::Display>, + justified: bool, + ) -> Result<()> { + let buffer = Self::format_message(status, message, style, justified)?; + self.stderr().write_all(&buffer)?; + Ok(()) + } + + /// Write a styled fragment + fn write_stdout(&mut self, fragment: impl fmt::Display, style: &Style) -> Result<()> { + let mut buffer = Vec::new(); + write!(buffer, "{style}{fragment}{style:#}")?; + self.stdout().write_all(&buffer)?; + Ok(()) + } + + /// Write a styled fragment + fn write_stderr(&mut self, fragment: impl fmt::Display, style: &Style) -> Result<()> { + let mut buffer = Vec::new(); + write!(buffer, "{style}{fragment}{style:#}")?; + self.stderr().write_all(&buffer)?; + Ok(()) + } + + /// Gets stdout as a [`io::Write`](Write) trait object. + #[inline] + fn stdout(&mut self) -> &mut dyn Write { + match self { + Self::Stream { stdout, .. } => stdout, + Self::Empty(e) => e, + } + } + + /// Gets stderr as a [`io::Write`](Write) trait object. + #[inline] + fn stderr(&mut self) -> &mut dyn Write { + match self { + Self::Stream { stderr, .. } => stderr, + Self::Empty(e) => e, + } + } + + /// Formats a message with a status and optional message. + fn format_message( + status: &dyn fmt::Display, + message: Option<&dyn fmt::Display>, + style: &Style, + justified: bool, + ) -> Result> { + let bold = anstyle::Style::new().bold(); + + let mut buffer = Vec::new(); + if justified { + write!(buffer, "{style}{status:>12}{style:#}")?; + } else { + write!(buffer, "{style}{status}{style:#}{bold}:{bold:#}")?; + } + match message { + Some(message) => { + writeln!(buffer, " {message}")?; + } + None => write!(buffer, " ")?, + } + + Ok(buffer) + } +} + +impl ColorChoice { + /// Converts our color choice to [`anstream`]'s version. + #[inline] + fn to_anstream_color_choice(self) -> anstream::ColorChoice { + match self { + Self::Always => anstream::ColorChoice::Always, + Self::Never => anstream::ColorChoice::Never, + Self::Auto => anstream::ColorChoice::Auto, + } + } +} + +#[inline] +fn supports_color(choice: anstream::ColorChoice) -> bool { + match choice { + anstream::ColorChoice::Always | + anstream::ColorChoice::AlwaysAnsi | + anstream::ColorChoice::Auto => true, + anstream::ColorChoice::Never => false, + } +} diff --git a/crates/cli/src/stdin.rs b/crates/common/src/io/stdin.rs similarity index 76% rename from crates/cli/src/stdin.rs rename to crates/common/src/io/stdin.rs index 8242cc805..17b40a2cf 100644 --- a/crates/cli/src/stdin.rs +++ b/crates/common/src/io/stdin.rs @@ -7,37 +7,6 @@ use std::{ str::FromStr, }; -/// Prints a message to [`stdout`][io::stdout] and [reads a line from stdin into a String](read). -/// -/// Returns `Result`, so sometimes `T` must be explicitly specified, like in `str::parse`. -/// -/// # Examples -/// -/// ```no_run -/// # use foundry_cli::prompt; -/// let response: String = prompt!("Would you like to continue? [y/N] ")?; -/// if !matches!(response.as_str(), "y" | "Y") { -/// return Ok(()) -/// } -/// # Ok::<(), Box>(()) -/// ``` -#[macro_export] -macro_rules! prompt { - () => { - $crate::stdin::parse_line() - }; - - ($($tt:tt)+) => { - { - ::std::print!($($tt)+); - match ::std::io::Write::flush(&mut ::std::io::stdout()) { - ::core::result::Result::Ok(_) => $crate::prompt!(), - ::core::result::Result::Err(e) => ::core::result::Result::Err(::eyre::eyre!("Could not flush stdout: {}", e)) - } - } - }; -} - /// Unwraps the given `Option` or [reads stdin into a String](read) and parses it as `T`. pub fn unwrap(value: Option, read_line: bool) -> Result where @@ -50,6 +19,7 @@ where } } +/// Shortcut for `(unwrap(a), unwrap(b))`. #[inline] pub fn unwrap2(a: Option, b: Option) -> Result<(A, B)> where diff --git a/crates/common/src/io/style.rs b/crates/common/src/io/style.rs new file mode 100644 index 000000000..6103b2d37 --- /dev/null +++ b/crates/common/src/io/style.rs @@ -0,0 +1,5 @@ +#![allow(missing_docs)] +use anstyle::*; + +pub const ERROR: Style = AnsiColor::Red.on_default().effects(Effects::BOLD); +pub const WARN: Style = AnsiColor::Yellow.on_default().effects(Effects::BOLD); diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index a33a7b223..68559d081 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -11,6 +11,9 @@ extern crate self as foundry_common; #[macro_use] extern crate tracing; +#[macro_use] +pub mod io; + pub use foundry_common_fmt as fmt; pub mod abi; @@ -26,7 +29,6 @@ pub mod provider; pub mod retry; pub mod selectors; pub mod serde_helpers; -pub mod shell; pub mod term; pub mod traits; pub mod transactions; @@ -34,6 +36,7 @@ mod utils; pub use constants::*; pub use contracts::*; +pub use io::{shell, stdin, Shell}; pub use traits::*; pub use transactions::*; pub use utils::*; diff --git a/crates/common/src/provider/mod.rs b/crates/common/src/provider/mod.rs index fe7fd4ccc..4fb9e29ae 100644 --- a/crates/common/src/provider/mod.rs +++ b/crates/common/src/provider/mod.rs @@ -270,6 +270,9 @@ impl ProviderBuilder { client.set_poll_interval( chain .average_blocktime_hint() + // we cap the poll interval because if not provided, chain would default to + // mainnet + .map(|hint| hint.min(DEFAULT_UNKNOWN_CHAIN_BLOCK_TIME)) .unwrap_or(DEFAULT_UNKNOWN_CHAIN_BLOCK_TIME) .mul_f32(POLL_INTERVAL_BLOCK_TIME_SCALE_FACTOR), ); diff --git a/crates/common/src/provider/runtime_transport.rs b/crates/common/src/provider/runtime_transport.rs index 8362b46d6..a95969be5 100644 --- a/crates/common/src/provider/runtime_transport.rs +++ b/crates/common/src/provider/runtime_transport.rs @@ -187,7 +187,7 @@ impl RuntimeTransport { /// Connects to a WS transport. async fn connect_ws(&self) -> Result { let auth = self.jwt.as_ref().and_then(|jwt| build_auth(jwt.clone()).ok()); - let ws = WsConnect { url: self.url.to_string(), auth } + let ws = WsConnect { url: self.url.to_string(), auth, config: None } .into_service() .await .map_err(|e| RuntimeTransportError::TransportError(e, self.url.to_string()))?; diff --git a/crates/common/src/shell.rs b/crates/common/src/shell.rs deleted file mode 100644 index 8ab98e64a..000000000 --- a/crates/common/src/shell.rs +++ /dev/null @@ -1,307 +0,0 @@ -//! Helpers for printing to output - -use serde::Serialize; -use std::{ - error::Error, - fmt, io, - io::Write, - sync::{Arc, Mutex, OnceLock}, -}; - -/// Stores the configured shell for the duration of the program -static SHELL: OnceLock = OnceLock::new(); - -/// Error indicating that `set_hook` was unable to install the provided ErrorHook -#[derive(Clone, Copy, Debug)] -pub struct InstallError; - -impl fmt::Display for InstallError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("cannot install provided Shell, a shell has already been installed") - } -} - -impl Error for InstallError {} - -/// Install the provided shell -pub fn set_shell(shell: Shell) -> Result<(), InstallError> { - SHELL.set(shell).map_err(|_| InstallError) -} - -/// Runs the given closure with the current shell, or default shell if none was set -pub fn with_shell(f: F) -> R -where - F: FnOnce(&Shell) -> R, -{ - if let Some(shell) = SHELL.get() { - f(shell) - } else { - let shell = Shell::default(); - f(&shell) - } -} - -/// Prints the given message to the shell -pub fn println(msg: impl fmt::Display) -> io::Result<()> { - with_shell(|shell| if !shell.verbosity.is_silent() { shell.write_stdout(msg) } else { Ok(()) }) -} -/// Prints the given message to the shell -pub fn print_json(obj: &T) -> serde_json::Result<()> { - with_shell(|shell| shell.print_json(obj)) -} - -/// Prints the given message to the shell -pub fn eprintln(msg: impl fmt::Display) -> io::Result<()> { - with_shell(|shell| if !shell.verbosity.is_silent() { shell.write_stderr(msg) } else { Ok(()) }) -} - -/// Returns the configured verbosity -pub fn verbosity() -> Verbosity { - with_shell(|shell| shell.verbosity) -} - -/// An abstraction around console output that also considers verbosity -#[derive(Default)] -pub struct Shell { - /// Wrapper around stdout/stderr. - output: ShellOut, - /// How to emit messages. - verbosity: Verbosity, -} - -impl Shell { - /// Creates a new shell instance - pub fn new(output: ShellOut, verbosity: Verbosity) -> Self { - Self { output, verbosity } - } - - /// Returns a new shell that conforms to the specified verbosity arguments, where `json` - /// or `junit` takes higher precedence. - pub fn from_args(silent: bool, json: bool) -> Self { - match (silent, json) { - (_, true) => Self::json(), - (true, _) => Self::silent(), - _ => Default::default(), - } - } - - /// Returns a new shell that won't emit anything - pub fn silent() -> Self { - Self::from_verbosity(Verbosity::Silent) - } - - /// Returns a new shell that'll only emit json - pub fn json() -> Self { - Self::from_verbosity(Verbosity::Json) - } - - /// Creates a new shell instance with default output and the given verbosity - pub fn from_verbosity(verbosity: Verbosity) -> Self { - Self::new(Default::default(), verbosity) - } - - /// Write a fragment to stdout - /// - /// Caller is responsible for deciding whether [`Shell`] verbosity affects output. - pub fn write_stdout(&self, fragment: impl fmt::Display) -> io::Result<()> { - self.output.write_stdout(fragment) - } - - /// Write a fragment to stderr - /// - /// Caller is responsible for deciding whether [`Shell`] verbosity affects output. - pub fn write_stderr(&self, fragment: impl fmt::Display) -> io::Result<()> { - self.output.write_stderr(fragment) - } - - /// Prints the object to stdout as json - pub fn print_json(&self, obj: &T) -> serde_json::Result<()> { - if self.verbosity.is_json() { - let json = serde_json::to_string(&obj)?; - let _ = self.output.with_stdout(|out| writeln!(out, "{json}")); - } - Ok(()) - } - /// Prints the object to stdout as pretty json - pub fn pretty_print_json(&self, obj: &T) -> serde_json::Result<()> { - if self.verbosity.is_json() { - let json = serde_json::to_string_pretty(&obj)?; - let _ = self.output.with_stdout(|out| writeln!(out, "{json}")); - } - Ok(()) - } -} - -impl fmt::Debug for Shell { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.output { - ShellOut::Write(_) => { - f.debug_struct("Shell").field("verbosity", &self.verbosity).finish() - } - ShellOut::Stream => { - f.debug_struct("Shell").field("verbosity", &self.verbosity).finish() - } - } - } -} - -/// Helper trait for custom shell output -/// -/// Can be used for debugging -pub trait ShellWrite { - /// Write the fragment - fn write(&self, fragment: impl fmt::Display) -> io::Result<()>; - - /// Executes a closure on the current stdout - fn with_stdout(&self, f: F) -> R - where - for<'r> F: FnOnce(&'r mut (dyn Write + 'r)) -> R; - - /// Executes a closure on the current stderr - fn with_err(&self, f: F) -> R - where - for<'r> F: FnOnce(&'r mut (dyn Write + 'r)) -> R; -} - -/// A guarded shell output type -pub struct WriteShellOut(Arc>>); - -unsafe impl Send for WriteShellOut {} -unsafe impl Sync for WriteShellOut {} - -impl ShellWrite for WriteShellOut { - fn write(&self, fragment: impl fmt::Display) -> io::Result<()> { - if let Ok(mut lock) = self.0.lock() { - writeln!(lock, "{fragment}")?; - } - Ok(()) - } - /// Executes a closure on the current stdout - fn with_stdout(&self, f: F) -> R - where - for<'r> F: FnOnce(&'r mut (dyn Write + 'r)) -> R, - { - let mut lock = self.0.lock().unwrap(); - f(&mut *lock) - } - - /// Executes a closure on the current stderr - fn with_err(&self, f: F) -> R - where - for<'r> F: FnOnce(&'r mut (dyn Write + 'r)) -> R, - { - let mut lock = self.0.lock().unwrap(); - f(&mut *lock) - } -} - -/// A `Write`able object, either with or without color support -#[derive(Default)] -pub enum ShellOut { - /// A plain write object - /// - /// Can be used for debug purposes - Write(WriteShellOut), - /// Streams to `stdio` - #[default] - Stream, -} - -impl ShellOut { - /// Creates a new shell that writes to memory - pub fn memory() -> Self { - #[allow(clippy::box_default)] - #[allow(clippy::arc_with_non_send_sync)] - Self::Write(WriteShellOut(Arc::new(Mutex::new(Box::new(Vec::new()))))) - } - - /// Write a fragment to stdout - fn write_stdout(&self, fragment: impl fmt::Display) -> io::Result<()> { - match *self { - Self::Stream => { - let stdout = io::stdout(); - let mut handle = stdout.lock(); - writeln!(handle, "{fragment}")?; - } - Self::Write(ref w) => { - w.write(fragment)?; - } - } - Ok(()) - } - - /// Write output to stderr - fn write_stderr(&self, fragment: impl fmt::Display) -> io::Result<()> { - match *self { - Self::Stream => { - let stderr = io::stderr(); - let mut handle = stderr.lock(); - writeln!(handle, "{fragment}")?; - } - Self::Write(ref w) => { - w.write(fragment)?; - } - } - Ok(()) - } - - /// Executes a closure on the current stdout - fn with_stdout(&self, f: F) -> R - where - for<'r> F: FnOnce(&'r mut (dyn Write + 'r)) -> R, - { - match *self { - Self::Stream => { - let stdout = io::stdout(); - let mut handler = stdout.lock(); - f(&mut handler) - } - Self::Write(ref w) => w.with_stdout(f), - } - } - - /// Executes a closure on the current stderr - #[allow(unused)] - fn with_err(&self, f: F) -> R - where - for<'r> F: FnOnce(&'r mut (dyn Write + 'r)) -> R, - { - match *self { - Self::Stream => { - let stderr = io::stderr(); - let mut handler = stderr.lock(); - f(&mut handler) - } - Self::Write(ref w) => w.with_err(f), - } - } -} - -/// The requested verbosity of output. -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] -pub enum Verbosity { - /// only allow json output - Json, - /// print as is - #[default] - Normal, - /// print nothing - Silent, -} - -impl Verbosity { - /// Returns true if json mode - pub fn is_json(&self) -> bool { - matches!(self, Self::Json) - } - - /// Returns true if silent - pub fn is_silent(&self) -> bool { - matches!(self, Self::Silent) - } - - /// Returns true if normal verbosity - pub fn is_normal(&self) -> bool { - matches!(self, Self::Normal) - } -} diff --git a/crates/common/src/term.rs b/crates/common/src/term.rs index 032148b8e..2469fff63 100644 --- a/crates/common/src/term.rs +++ b/crates/common/src/term.rs @@ -207,21 +207,6 @@ pub fn with_spinner_reporter(f: impl FnOnce() -> T) -> T { report::with_scoped(&reporter, f) } -#[macro_export] -/// Displays warnings on the cli -macro_rules! cli_warn { - ($($arg:tt)*) => { - eprintln!( - "{}{} {}", - yansi::Painted::new("warning").yellow().bold(), - yansi::Painted::new(":").bold(), - format_args!($($arg)*) - ) - } -} - -pub use cli_warn; - #[cfg(test)] mod tests { use super::*; diff --git a/crates/common/src/transactions.rs b/crates/common/src/transactions.rs index 7335714e5..4ddef26dd 100644 --- a/crates/common/src/transactions.rs +++ b/crates/common/src/transactions.rs @@ -3,7 +3,7 @@ use alloy_consensus::{Transaction, TxEnvelope}; use alloy_primitives::{Address, TxKind, U256}; use alloy_provider::{ - network::{AnyNetwork, TransactionBuilder}, + network::{AnyNetwork, ReceiptResponse, TransactionBuilder}, Provider, }; use alloy_rpc_types::{AnyTransactionReceipt, BlockId, TransactionRequest}; @@ -122,7 +122,7 @@ pub fn get_pretty_tx_receipt_attr( "gasUsed" | "gas_used" => Some(receipt.receipt.gas_used.to_string()), "logs" => Some(receipt.receipt.inner.inner.inner.receipt.logs.as_slice().pretty()), "logsBloom" | "logs_bloom" => Some(receipt.receipt.inner.inner.inner.logs_bloom.pretty()), - "root" | "stateRoot" | "state_root " => Some(receipt.receipt.state_root.pretty()), + "root" | "stateRoot" | "state_root " => Some(receipt.receipt.state_root().pretty()), "status" | "statusCode" | "status_code" => { Some(receipt.receipt.inner.inner.inner.receipt.status.pretty()) } @@ -201,7 +201,7 @@ impl TransactionMaybeSigned { pub fn to(&self) -> Option { match self { - Self::Signed { tx, .. } => Some(tx.to()), + Self::Signed { tx, .. } => Some(tx.kind()), Self::Unsigned(tx) => tx.to, } } diff --git a/crates/config/src/fmt.rs b/crates/config/src/fmt.rs index 44fefe7d4..693811719 100644 --- a/crates/config/src/fmt.rs +++ b/crates/config/src/fmt.rs @@ -162,6 +162,8 @@ pub enum MultilineFuncHeaderStyle { /// If function params or attrs are multiline. /// split the rest All, + /// Same as `All` but writes function params multiline even when there is a single param. + AllParams, } impl Default for FormatterConfig { diff --git a/crates/config/src/invariant.rs b/crates/config/src/invariant.rs index c81827c61..a53a38a7d 100644 --- a/crates/config/src/invariant.rs +++ b/crates/config/src/invariant.rs @@ -34,6 +34,8 @@ pub struct InvariantConfig { pub gas_report_samples: u32, /// Path where invariant failures are recorded and replayed. pub failure_persist_dir: Option, + /// Whether to collect and display fuzzed selectors metrics. + pub show_metrics: bool, /// When enabled, filters all addresses below 2^16, as they are reserved in zkSync. pub no_zksync_reserved_addresses: bool, } @@ -50,6 +52,7 @@ impl Default for InvariantConfig { max_assume_rejects: 65536, gas_report_samples: 256, failure_persist_dir: None, + show_metrics: false, no_zksync_reserved_addresses: false, } } @@ -68,6 +71,7 @@ impl InvariantConfig { max_assume_rejects: 65536, gas_report_samples: 256, failure_persist_dir: Some(cache_dir), + show_metrics: false, no_zksync_reserved_addresses: false, } } @@ -107,6 +111,7 @@ impl InlineConfigParser for InvariantConfig { conf_clone.failure_persist_dir = Some(PathBuf::from(value)) } "shrink-run-limit" => conf_clone.shrink_run_limit = parse_config_u32(key, value)?, + "show-metrics" => conf_clone.show_metrics = parse_config_bool(key, value)?, "no-zksync-reserved-addresses" => { conf_clone.no_zksync_reserved_addresses = parse_config_bool(key, value)? } diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 8a729f0b1..a017da8a1 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -198,6 +198,8 @@ pub struct Config { pub gas_reports: Vec, /// list of contracts to ignore for gas reports pub gas_reports_ignore: Vec, + /// Whether to include gas reports for tests. + pub gas_reports_include_tests: bool, /// The Solc instance to use if any. /// /// This takes precedence over `auto_detect_solc`, if a version is set then this overrides @@ -240,6 +242,8 @@ pub struct Config { pub eth_rpc_url: Option, /// JWT secret that should be used for any rpc calls pub eth_rpc_jwt: Option, + /// Timeout that should be used for any rpc calls + pub eth_rpc_timeout: Option, /// etherscan API key, or alias for an `EtherscanConfig` in `etherscan` table pub etherscan_api_key: Option, /// Multiple etherscan api configs and their aliases @@ -2211,6 +2215,7 @@ impl Default for Config { evm_version: EvmVersion::default(), gas_reports: vec!["*".to_string()], gas_reports_ignore: vec![], + gas_reports_include_tests: false, solc: None, vyper: Default::default(), auto_detect_solc: true, @@ -2257,6 +2262,7 @@ impl Default for Config { memory_limit: 1 << 27, // 2**27 = 128MiB = 134_217_728 bytes eth_rpc_url: None, eth_rpc_jwt: None, + eth_rpc_timeout: None, etherscan_api_key: None, verbosity: 0, remappings: vec![], diff --git a/crates/config/src/providers/remappings.rs b/crates/config/src/providers/remappings.rs index 2e849bea4..48e9c875f 100644 --- a/crates/config/src/providers/remappings.rs +++ b/crates/config/src/providers/remappings.rs @@ -46,14 +46,16 @@ impl Remappings { } /// Push an element to the remappings vector, but only if it's not already present. - pub fn push(&mut self, remapping: Remapping) { + fn push(&mut self, remapping: Remapping) { if !self.remappings.iter().any(|existing| { // What we're doing here is filtering for ambiguous paths. For example, if we have - // @prb/math/=node_modules/@prb/math/src/ as existing, and - // @prb/=node_modules/@prb/ as the one being checked, + // @prb/=node_modules/@prb/ as existing, and + // @prb/math/=node_modules/@prb/math/src/ as the one being checked, // we want to keep the already existing one, which is the first one. This way we avoid // having to deal with ambiguous paths which is unwanted when autodetecting remappings. - existing.name.starts_with(&remapping.name) && existing.context == remapping.context + // Remappings are added from root of the project down to libraries, so + // we want to exclude any conflicting remappings added from libraries. + remapping.name.starts_with(&existing.name) && existing.context == remapping.context }) { self.remappings.push(remapping) } diff --git a/crates/config/src/utils.rs b/crates/config/src/utils.rs index b1434bc7a..2117834f4 100644 --- a/crates/config/src/utils.rs +++ b/crates/config/src/utils.rs @@ -301,7 +301,7 @@ impl FromStr for Numeric { #[inline] pub fn evm_spec_id(evm_version: &EvmVersion, alphanet: bool) -> SpecId { if alphanet { - return SpecId::PRAGUE_EOF; + return SpecId::OSAKA; } match evm_version { EvmVersion::Homestead => SpecId::HOMESTEAD, @@ -316,7 +316,7 @@ pub fn evm_spec_id(evm_version: &EvmVersion, alphanet: bool) -> SpecId { EvmVersion::Paris => SpecId::MERGE, EvmVersion::Shanghai => SpecId::SHANGHAI, EvmVersion::Cancun => SpecId::CANCUN, - EvmVersion::Prague => SpecId::PRAGUE_EOF, + EvmVersion::Prague => SpecId::OSAKA, // Osaka enables EOF } } diff --git a/crates/config/src/zksync.rs b/crates/config/src/zksync.rs index 8d86eaa41..95370e5a9 100644 --- a/crates/config/src/zksync.rs +++ b/crates/config/src/zksync.rs @@ -6,14 +6,15 @@ use foundry_compilers::{ solc::CliSettings, zksolc::{ settings::{ - BytecodeHash, Codegen, Optimizer, OptimizerDetails, SettingsMetadata, ZkSolcSettings, + BytecodeHash, Codegen, Optimizer, OptimizerDetails, SettingsMetadata, ZkSolcError, + ZkSolcSettings, ZkSolcWarning, }, ZkSettings, }, }; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; +use std::{collections::HashSet, path::PathBuf}; use crate::SolcReq; @@ -61,6 +62,12 @@ pub struct ZkSyncConfig { /// zkSolc optimizer details pub optimizer_details: Option, + + // zksolc suppressed warnings. + pub suppressed_warnings: HashSet, + + // zksolc suppressed errors. + pub suppressed_errors: HashSet, } impl Default for ZkSyncConfig { @@ -80,6 +87,8 @@ impl Default for ZkSyncConfig { optimizer: true, optimizer_mode: '3', optimizer_details: Default::default(), + suppressed_errors: Default::default(), + suppressed_warnings: Default::default(), } } } @@ -130,6 +139,8 @@ impl ZkSyncConfig { }, }, codegen: if self.force_evmla { Codegen::EVMLA } else { Codegen::Yul }, + suppressed_warnings: self.suppressed_warnings.clone(), + suppressed_errors: self.suppressed_errors.clone(), }; // `cli_settings` get set from `Project` values when building `ZkSolcVersionedInput` diff --git a/crates/debugger/src/tui/builder.rs b/crates/debugger/src/builder.rs similarity index 99% rename from crates/debugger/src/tui/builder.rs rename to crates/debugger/src/builder.rs index 484611c70..fd2dce3df 100644 --- a/crates/debugger/src/tui/builder.rs +++ b/crates/debugger/src/builder.rs @@ -1,4 +1,4 @@ -//! TUI debugger builder. +//! Debugger builder. use crate::{node::flatten_call_trace, DebugNode, Debugger}; use alloy_primitives::{map::AddressHashMap, Address}; diff --git a/crates/debugger/src/debugger.rs b/crates/debugger/src/debugger.rs new file mode 100644 index 000000000..0e4de437c --- /dev/null +++ b/crates/debugger/src/debugger.rs @@ -0,0 +1,73 @@ +//! Debugger implementation. + +use crate::{tui::TUI, DebugNode, DebuggerBuilder, ExitReason, FileDumper}; +use alloy_primitives::map::AddressHashMap; +use eyre::Result; +use foundry_common::evm::Breakpoints; +use foundry_evm_traces::debug::ContractSources; +use std::path::PathBuf; + +pub struct DebuggerContext { + pub debug_arena: Vec, + pub identified_contracts: AddressHashMap, + /// Source map of contract sources + pub contracts_sources: ContractSources, + pub breakpoints: Breakpoints, +} + +pub struct Debugger { + context: DebuggerContext, +} + +impl Debugger { + /// Creates a new debugger builder. + #[inline] + pub fn builder() -> DebuggerBuilder { + DebuggerBuilder::new() + } + + /// Creates a new debugger. + pub fn new( + debug_arena: Vec, + identified_contracts: AddressHashMap, + contracts_sources: ContractSources, + breakpoints: Breakpoints, + ) -> Self { + Self { + context: DebuggerContext { + debug_arena, + identified_contracts, + contracts_sources, + breakpoints, + }, + } + } + + /// Starts the debugger TUI. Terminates the current process on failure or user exit. + pub fn run_tui_exit(mut self) -> ! { + let code = match self.try_run_tui() { + Ok(ExitReason::CharExit) => 0, + Err(e) => { + println!("{e}"); + 1 + } + }; + std::process::exit(code) + } + + /// Starts the debugger TUI. + pub fn try_run_tui(&mut self) -> Result { + eyre::ensure!(!self.context.debug_arena.is_empty(), "debug arena is empty"); + + let mut tui = TUI::new(&mut self.context); + tui.try_run() + } + + /// Dumps debugger data to file. + pub fn dump_to_file(&mut self, path: &PathBuf) -> Result<()> { + eyre::ensure!(!self.context.debug_arena.is_empty(), "debug arena is empty"); + + let mut file_dumper = FileDumper::new(path, &mut self.context); + file_dumper.run() + } +} diff --git a/crates/debugger/src/file_dumper.rs b/crates/debugger/src/file_dumper.rs new file mode 100644 index 000000000..909530c42 --- /dev/null +++ b/crates/debugger/src/file_dumper.rs @@ -0,0 +1,172 @@ +//! The debug file dumper implementation. + +use crate::{debugger::DebuggerContext, DebugNode}; +use alloy_primitives::Address; +use eyre::Result; +use foundry_common::fs::write_json_file; +use foundry_compilers::{ + artifacts::sourcemap::{Jump, SourceElement}, + multi::MultiCompilerLanguage, +}; +use foundry_evm_traces::debug::{ArtifactData, ContractSources, SourceData}; +use serde::Serialize; +use std::{collections::HashMap, ops::Deref, path::PathBuf}; + +/// Generates and writes debugger dump in a json file. +pub struct FileDumper<'a> { + /// Path to json file to write dump into. + path: &'a PathBuf, + /// Debugger context to generate dump for. + debugger_context: &'a mut DebuggerContext, +} + +impl<'a> FileDumper<'a> { + pub fn new(path: &'a PathBuf, debugger_context: &'a mut DebuggerContext) -> Self { + Self { path, debugger_context } + } + + pub fn run(&mut self) -> Result<()> { + let data = DebuggerDump::from(self.debugger_context); + write_json_file(self.path, &data).unwrap(); + Ok(()) + } +} + +/// Holds info of debugger dump. +#[derive(Serialize)] +struct DebuggerDump { + contracts: ContractsDump, + debug_arena: Vec, +} + +impl DebuggerDump { + fn from(debugger_context: &DebuggerContext) -> Self { + Self { + contracts: ContractsDump::new(debugger_context), + debug_arena: debugger_context.debug_arena.clone(), + } + } +} + +#[derive(Serialize)] +pub struct SourceElementDump { + offset: u32, + length: u32, + index: i32, + jump: u32, + modifier_depth: u32, +} + +impl SourceElementDump { + pub fn new(v: &SourceElement) -> Self { + Self { + offset: v.offset(), + length: v.length(), + index: v.index_i32(), + jump: match v.jump() { + Jump::In => 0, + Jump::Out => 1, + Jump::Regular => 2, + }, + modifier_depth: v.modifier_depth(), + } + } +} + +#[derive(Serialize)] +struct ContractsDump { + // Map of call address to contract name + identified_contracts: HashMap, + sources: ContractsSourcesDump, +} + +impl ContractsDump { + pub fn new(debugger_context: &DebuggerContext) -> Self { + Self { + identified_contracts: debugger_context + .identified_contracts + .iter() + .map(|(k, v)| (*k, v.clone())) + .collect(), + sources: ContractsSourcesDump::new(&debugger_context.contracts_sources), + } + } +} + +#[derive(Serialize)] +struct ContractsSourcesDump { + sources_by_id: HashMap>, + artifacts_by_name: HashMap>, +} + +impl ContractsSourcesDump { + pub fn new(contracts_sources: &ContractSources) -> Self { + Self { + sources_by_id: contracts_sources + .sources_by_id + .iter() + .map(|(name, inner_map)| { + ( + name.clone(), + inner_map + .iter() + .map(|(id, source_data)| (*id, SourceDataDump::new(source_data))) + .collect(), + ) + }) + .collect(), + artifacts_by_name: contracts_sources + .artifacts_by_name + .iter() + .map(|(name, data)| { + (name.clone(), data.iter().map(ArtifactDataDump::new).collect()) + }) + .collect(), + } + } +} + +#[derive(Serialize)] +struct SourceDataDump { + source: String, + language: MultiCompilerLanguage, + path: PathBuf, +} + +impl SourceDataDump { + pub fn new(v: &SourceData) -> Self { + Self { source: v.source.deref().clone(), language: v.language, path: v.path.clone() } + } +} + +#[derive(Serialize)] +struct ArtifactDataDump { + pub source_map: Option>, + pub source_map_runtime: Option>, + pub pc_ic_map: Option>, + pub pc_ic_map_runtime: Option>, + pub build_id: String, + pub file_id: u32, +} + +impl ArtifactDataDump { + pub fn new(v: &ArtifactData) -> Self { + Self { + source_map: v + .source_map + .clone() + .map(|source_map| source_map.iter().map(SourceElementDump::new).collect()), + source_map_runtime: v + .source_map_runtime + .clone() + .map(|source_map| source_map.iter().map(SourceElementDump::new).collect()), + pc_ic_map: v.pc_ic_map.clone().map(|v| v.inner.iter().map(|(k, v)| (*k, *v)).collect()), + pc_ic_map_runtime: v + .pc_ic_map_runtime + .clone() + .map(|v| v.inner.iter().map(|(k, v)| (*k, *v)).collect()), + build_id: v.build_id.clone(), + file_id: v.file_id, + } + } +} diff --git a/crates/debugger/src/lib.rs b/crates/debugger/src/lib.rs index 678ae8672..aa561973c 100644 --- a/crates/debugger/src/lib.rs +++ b/crates/debugger/src/lib.rs @@ -1,6 +1,6 @@ //! # foundry-debugger //! -//! Interactive Solidity TUI debugger. +//! Interactive Solidity TUI debugger and debugger data file dumper #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] @@ -10,8 +10,16 @@ extern crate tracing; mod op; +mod builder; +mod debugger; +mod file_dumper; mod tui; -pub use tui::{Debugger, DebuggerBuilder, ExitReason}; mod node; + pub use node::DebugNode; + +pub use builder::DebuggerBuilder; +pub use debugger::Debugger; +pub use file_dumper::FileDumper; +pub use tui::{ExitReason, TUI}; diff --git a/crates/debugger/src/tui/context.rs b/crates/debugger/src/tui/context.rs index c3645e31b..0c61a1fcd 100644 --- a/crates/debugger/src/tui/context.rs +++ b/crates/debugger/src/tui/context.rs @@ -1,6 +1,6 @@ //! Debugger context and event handler implementation. -use crate::{DebugNode, Debugger, ExitReason}; +use crate::{debugger::DebuggerContext, DebugNode, ExitReason}; use alloy_primitives::{hex, Address}; use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent, MouseEventKind}; use foundry_evm_core::buffer::BufferKind; @@ -16,8 +16,8 @@ pub(crate) struct DrawMemory { pub(crate) current_stack_startline: usize, } -pub(crate) struct DebuggerContext<'a> { - pub(crate) debugger: &'a mut Debugger, +pub(crate) struct TUIContext<'a> { + pub(crate) debugger_context: &'a mut DebuggerContext, /// Buffer for keys prior to execution, i.e. '10' + 'k' => move up 10 operations. pub(crate) key_buffer: String, @@ -35,10 +35,10 @@ pub(crate) struct DebuggerContext<'a> { pub(crate) active_buffer: BufferKind, } -impl<'a> DebuggerContext<'a> { - pub(crate) fn new(debugger: &'a mut Debugger) -> Self { - DebuggerContext { - debugger, +impl<'a> TUIContext<'a> { + pub(crate) fn new(debugger_context: &'a mut DebuggerContext) -> Self { + TUIContext { + debugger_context, key_buffer: String::with_capacity(64), current_step: 0, @@ -58,7 +58,7 @@ impl<'a> DebuggerContext<'a> { } pub(crate) fn debug_arena(&self) -> &[DebugNode] { - &self.debugger.debug_arena + &self.debugger_context.debug_arena } pub(crate) fn debug_call(&self) -> &DebugNode { @@ -87,7 +87,8 @@ impl<'a> DebuggerContext<'a> { fn gen_opcode_list(&mut self) { self.opcode_list.clear(); - let debug_steps = &self.debugger.debug_arena[self.draw_memory.inner_call_index].steps; + let debug_steps = + &self.debugger_context.debug_arena[self.draw_memory.inner_call_index].steps; for step in debug_steps { self.opcode_list.push(pretty_opcode(step)); } @@ -109,7 +110,7 @@ impl<'a> DebuggerContext<'a> { } } -impl DebuggerContext<'_> { +impl TUIContext<'_> { pub(crate) fn handle_event(&mut self, event: Event) -> ControlFlow { let ret = match event { Event::Key(event) => self.handle_key_event(event), @@ -259,7 +260,7 @@ impl DebuggerContext<'_> { fn handle_breakpoint(&mut self, c: char) { // Find the location of the called breakpoint in the whole debug arena (at this address with // this pc) - if let Some((caller, pc)) = self.debugger.breakpoints.get(&c) { + if let Some((caller, pc)) = self.debugger_context.breakpoints.get(&c) { for (i, node) in self.debug_arena().iter().enumerate() { if node.address == *caller { if let Some(step) = node.steps.iter().position(|step| step.pc == *pc) { diff --git a/crates/debugger/src/tui/draw.rs b/crates/debugger/src/tui/draw.rs index 55e4834f5..18b589279 100644 --- a/crates/debugger/src/tui/draw.rs +++ b/crates/debugger/src/tui/draw.rs @@ -1,6 +1,6 @@ //! TUI draw implementation. -use super::context::DebuggerContext; +use super::context::TUIContext; use crate::op::OpcodeParam; use foundry_compilers::artifacts::sourcemap::SourceElement; use foundry_evm_core::buffer::{get_buffer_accesses, BufferKind}; @@ -15,7 +15,7 @@ use ratatui::{ use revm_inspectors::tracing::types::CallKind; use std::{collections::VecDeque, fmt::Write, io}; -impl DebuggerContext<'_> { +impl TUIContext<'_> { /// Draws the TUI layout and subcomponents to the given terminal. pub(crate) fn draw(&self, terminal: &mut super::DebuggerTerminal) -> io::Result<()> { terminal.draw(|f| self.draw_layout(f)).map(drop) @@ -343,11 +343,11 @@ impl DebuggerContext<'_> { /// Returns source map, source code and source name of the current line. fn src_map(&self) -> Result<(SourceElement, &SourceData), String> { let address = self.address(); - let Some(contract_name) = self.debugger.identified_contracts.get(address) else { + let Some(contract_name) = self.debugger_context.identified_contracts.get(address) else { return Err(format!("Unknown contract at address {address}")); }; - self.debugger + self.debugger_context .contracts_sources .find_source_mapping( contract_name, diff --git a/crates/debugger/src/tui/mod.rs b/crates/debugger/src/tui/mod.rs index 75b747a7e..abc7c4a97 100644 --- a/crates/debugger/src/tui/mod.rs +++ b/crates/debugger/src/tui/mod.rs @@ -1,14 +1,11 @@ //! The TUI implementation. -use alloy_primitives::map::AddressHashMap; use crossterm::{ event::{self, DisableMouseCapture, EnableMouseCapture, Event}, execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; use eyre::Result; -use foundry_common::evm::Breakpoints; -use foundry_evm_traces::debug::ContractSources; use ratatui::{ backend::{Backend, CrosstermBackend}, Terminal, @@ -21,13 +18,9 @@ use std::{ time::{Duration, Instant}, }; -mod builder; -pub use builder::DebuggerBuilder; - mod context; -use context::DebuggerContext; - -use crate::DebugNode; +use crate::debugger::DebuggerContext; +use context::TUIContext; mod draw; @@ -41,47 +34,18 @@ pub enum ExitReason { } /// The TUI debugger. -pub struct Debugger { - debug_arena: Vec, - identified_contracts: AddressHashMap, - /// Source map of contract sources - contracts_sources: ContractSources, - breakpoints: Breakpoints, +pub struct TUI<'a> { + debugger_context: &'a mut DebuggerContext, } -impl Debugger { - /// Creates a new debugger builder. - #[inline] - pub fn builder() -> DebuggerBuilder { - DebuggerBuilder::new() - } - +impl<'a> TUI<'a> { /// Creates a new debugger. - pub fn new( - debug_arena: Vec, - identified_contracts: AddressHashMap, - contracts_sources: ContractSources, - breakpoints: Breakpoints, - ) -> Self { - Self { debug_arena, identified_contracts, contracts_sources, breakpoints } - } - - /// Starts the debugger TUI. Terminates the current process on failure or user exit. - pub fn run_exit(mut self) -> ! { - let code = match self.try_run() { - Ok(ExitReason::CharExit) => 0, - Err(e) => { - println!("{e}"); - 1 - } - }; - std::process::exit(code) + pub fn new(debugger_context: &'a mut DebuggerContext) -> Self { + Self { debugger_context } } /// Starts the debugger TUI. pub fn try_run(&mut self) -> Result { - eyre::ensure!(!self.debug_arena.is_empty(), "debug arena is empty"); - let backend = CrosstermBackend::new(io::stdout()); let terminal = Terminal::new(backend)?; TerminalGuard::with(terminal, |terminal| self.try_run_real(terminal)) @@ -90,7 +54,7 @@ impl Debugger { #[instrument(target = "debugger", name = "run", skip_all, ret)] fn try_run_real(&mut self, terminal: &mut DebuggerTerminal) -> Result { // Create the context. - let mut cx = DebuggerContext::new(self); + let mut cx = TUIContext::new(self.debugger_context); cx.init(); diff --git a/crates/doc/src/parser/comment.rs b/crates/doc/src/parser/comment.rs index 4954cd7cd..bf2b0ad7b 100644 --- a/crates/doc/src/parser/comment.rs +++ b/crates/doc/src/parser/comment.rs @@ -1,10 +1,10 @@ use alloy_primitives::map::HashMap; -use derive_more::{Deref, DerefMut}; +use derive_more::{derive::Display, Deref, DerefMut}; use solang_parser::doccomment::DocCommentTag; /// The natspec comment tag explaining the purpose of the comment. /// See: . -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Display, PartialEq, Eq)] pub enum CommentTag { /// A title that should describe the contract/interface Title, diff --git a/crates/doc/src/writer/as_doc.rs b/crates/doc/src/writer/as_doc.rs index d68f7a8e5..56a0a4026 100644 --- a/crates/doc/src/writer/as_doc.rs +++ b/crates/doc/src/writer/as_doc.rs @@ -64,8 +64,9 @@ impl AsDoc for CommentsRef<'_> { writer.write_bold(&format!("Note{}:", if customs.len() == 1 { "" } else { "s" }))?; for c in customs.iter() { writer.writeln_raw(format!( - "{}{}", + "{}{}: {}", if customs.len() == 1 { "" } else { "- " }, + &c.tag, &c.value ))?; writer.writeln()?; diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 1cac94852..5784c7ad2 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -23,8 +23,8 @@ use revm::{ inspectors::NoOpInspector, precompile::{PrecompileSpecId, Precompiles}, primitives::{ - Account, AccountInfo, Bytecode, Env, EnvWithHandlerCfg, EvmState, EvmStorageSlot, - HashMap as Map, Log, ResultAndState, SpecId, KECCAK_EMPTY, + Account, AccountInfo, BlobExcessGasAndPrice, Bytecode, Env, EnvWithHandlerCfg, EvmState, + EvmStorageSlot, HashMap as Map, Log, ResultAndState, SpecId, KECCAK_EMPTY, }, Database, DatabaseCommit, JournaledState, }; @@ -1980,25 +1980,33 @@ fn merge_db_account_data( active: &CacheDB, fork_db: &mut ForkDB, ) { - let mut acc = if let Some(acc) = active.accounts.get(&addr).cloned() { - acc - } else { - // Account does not exist - return; - }; + trace!(?addr, "merging database data"); - if let Some(code) = active.contracts.get(&acc.info.code_hash).cloned() { - fork_db.contracts.insert(acc.info.code_hash, code); - } + let Some(acc) = active.accounts.get(&addr) else { return }; - if let Some(fork_account) = fork_db.accounts.get_mut(&addr) { - // This will merge the fork's tracked storage with active storage and update values - fork_account.storage.extend(std::mem::take(&mut acc.storage)); - // swap them so we can insert the account as whole in the next step - std::mem::swap(&mut fork_account.storage, &mut acc.storage); + // port contract cache over + if let Some(code) = active.contracts.get(&acc.info.code_hash) { + trace!("merging contract cache"); + fork_db.contracts.insert(acc.info.code_hash, code.clone()); } - fork_db.accounts.insert(addr, acc); + // port account storage over + use std::collections::hash_map::Entry; + match fork_db.accounts.entry(addr) { + Entry::Vacant(vacant) => { + trace!("target account not present - inserting from active"); + // if the fork_db doesn't have the target account + // insert the entire thing + vacant.insert(acc.clone()); + } + Entry::Occupied(mut occupied) => { + trace!("target account present - merging storage slots"); + // if the fork_db does have the system, + // extend the existing storage (overriding) + let fork_account = occupied.get_mut(); + fork_account.storage.extend(&acc.storage); + } + } } /// Clones the zk account data from the `active` db into the `ForkDB` @@ -2064,6 +2072,8 @@ fn update_env_block(env: &mut Env, block: &Block) { env.block.basefee = U256::from(block.header.base_fee_per_gas.unwrap_or_default()); env.block.gas_limit = U256::from(block.header.gas_limit); env.block.number = U256::from(block.header.number); + env.block.blob_excess_gas_and_price = + block.header.excess_blob_gas.map(BlobExcessGasAndPrice::new); } /// Executes the given transaction and commits state changes to the database _and_ the journaled @@ -2077,6 +2087,12 @@ fn commit_transaction( persistent_accounts: &HashSet
, inspector: &mut dyn InspectorExt, ) -> eyre::Result<()> { + // TODO: Remove after https://github.com/foundry-rs/foundry/pull/9131 + // if the tx has the blob_versioned_hashes field, we assume it's a Cancun block + if tx.blob_versioned_hashes.is_some() { + env.handler_cfg.spec_id = SpecId::CANCUN; + } + configure_tx_env(&mut env.env, tx); let now = Instant::now(); diff --git a/crates/evm/evm/Cargo.toml b/crates/evm/evm/Cargo.toml index 65966dfa5..ca0287b65 100644 --- a/crates/evm/evm/Cargo.toml +++ b/crates/evm/evm/Cargo.toml @@ -52,3 +52,4 @@ proptest.workspace = true thiserror.workspace = true tracing.workspace = true indicatif = "0.17" +serde.workspace = true diff --git a/crates/evm/evm/src/executors/invariant/mod.rs b/crates/evm/evm/src/executors/invariant/mod.rs index e8dcea10b..b4a46d775 100644 --- a/crates/evm/evm/src/executors/invariant/mod.rs +++ b/crates/evm/evm/src/executors/invariant/mod.rs @@ -30,7 +30,11 @@ use proptest::{ use result::{assert_after_invariant, assert_invariants, can_continue}; use revm::primitives::HashMap; use shrink::shrink_sequence; -use std::{cell::RefCell, collections::btree_map::Entry, sync::Arc}; +use std::{ + cell::RefCell, + collections::{btree_map::Entry, HashMap as Map}, + sync::Arc, +}; mod error; pub use error::{InvariantFailures, InvariantFuzzError}; @@ -41,6 +45,7 @@ pub use replay::{replay_error, replay_run}; mod result; pub use result::InvariantFuzzTestResult; +use serde::{Deserialize, Serialize}; mod shrink; use crate::executors::EvmError; @@ -100,6 +105,17 @@ sol! { } } +/// Contains invariant metrics for a single fuzzed selector. +#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +pub struct InvariantMetrics { + // Count of fuzzed selector calls. + pub calls: usize, + // Count of fuzzed selector reverts. + pub reverts: usize, + // Count of fuzzed selector discards (through assume cheatcodes). + pub discards: usize, +} + /// Contains data collected during invariant test runs. pub struct InvariantTestData { // Consumed gas and calldata of every successful fuzz call. @@ -114,6 +130,8 @@ pub struct InvariantTestData { pub last_call_results: Option, // Coverage information collected from all fuzzed calls. pub coverage: Option, + // Metrics for each fuzzed selector. + pub metrics: Map, // Proptest runner to query for random values. // The strategy only comes with the first `input`. We fill the rest of the `inputs` @@ -152,6 +170,7 @@ impl InvariantTest { gas_report_traces: vec![], last_call_results, coverage: None, + metrics: Map::default(), branch_runner, }); Self { fuzz_state, targeted_contracts, execution_data } @@ -190,6 +209,24 @@ impl InvariantTest { } } + /// Update metrics for a fuzzed selector, extracted from tx details. + /// Always increments number of calls; discarded runs (through assume cheatcodes) are tracked + /// separated from reverts. + pub fn record_metrics(&self, tx_details: &BasicTxDetails, reverted: bool, discarded: bool) { + if let Some(metric_key) = + self.targeted_contracts.targets.lock().fuzzed_metric_key(tx_details) + { + let test_metrics = &mut self.execution_data.borrow_mut().metrics; + let invariant_metrics = test_metrics.entry(metric_key).or_default(); + invariant_metrics.calls += 1; + if discarded { + invariant_metrics.discards += 1; + } else if reverted { + invariant_metrics.reverts += 1; + } + } + } + /// End invariant test run by collecting results, cleaning collected artifacts and reverting /// created fuzz state. pub fn end_run(&self, run: InvariantTestRun, gas_samples: usize) { @@ -330,10 +367,15 @@ impl<'a> InvariantExecutor<'a> { TestCaseError::fail(format!("Could not make raw evm call: {e}")) })?; + let discarded = call_result.result.as_ref() == MAGIC_ASSUME; + if self.config.show_metrics { + invariant_test.record_metrics(tx, call_result.reverted, discarded); + } + // Collect coverage from last fuzzed call. invariant_test.merge_coverage(call_result.coverage.clone()); - if call_result.result.as_ref() == MAGIC_ASSUME { + if discarded { current_run.inputs.pop(); current_run.assume_rejects_counter += 1; if current_run.assume_rejects_counter > self.config.max_assume_rejects { @@ -442,6 +484,7 @@ impl<'a> InvariantExecutor<'a> { last_run_inputs: result.last_run_inputs, gas_report_traces: result.gas_report_traces, coverage: result.coverage, + metrics: result.metrics, }) } diff --git a/crates/evm/evm/src/executors/invariant/result.rs b/crates/evm/evm/src/executors/invariant/result.rs index c6a15930c..8920a1209 100644 --- a/crates/evm/evm/src/executors/invariant/result.rs +++ b/crates/evm/evm/src/executors/invariant/result.rs @@ -1,6 +1,6 @@ use super::{ call_after_invariant_function, call_invariant_function, error::FailedInvariantCaseData, - InvariantFailures, InvariantFuzzError, InvariantTest, InvariantTestRun, + InvariantFailures, InvariantFuzzError, InvariantMetrics, InvariantTest, InvariantTestRun, }; use crate::executors::{Executor, RawCallResult}; use alloy_dyn_abi::JsonAbiExt; @@ -13,7 +13,7 @@ use foundry_evm_fuzz::{ FuzzedCases, }; use revm_inspectors::tracing::CallTraceArena; -use std::borrow::Cow; +use std::{borrow::Cow, collections::HashMap}; /// The outcome of an invariant fuzz test #[derive(Debug)] @@ -30,6 +30,8 @@ pub struct InvariantFuzzTestResult { pub gas_report_traces: Vec>, /// The coverage info collected during the invariant test runs. pub coverage: Option, + /// Fuzzed selectors metrics collected during the invariant test runs. + pub metrics: HashMap, } /// Enriched results of an invariant run check. diff --git a/crates/evm/evm/src/executors/mod.rs b/crates/evm/evm/src/executors/mod.rs index a3c14b992..8fcd7627d 100644 --- a/crates/evm/evm/src/executors/mod.rs +++ b/crates/evm/evm/src/executors/mod.rs @@ -732,7 +732,7 @@ pub enum EvmError { Skip(SkipReason), /// Any other error. #[error(transparent)] - Eyre(#[from] eyre::Error), + Eyre(eyre::Error), } impl From for EvmError { @@ -747,6 +747,16 @@ impl From for EvmError { } } +impl From for EvmError { + fn from(err: eyre::Report) -> Self { + let mut chained_cause = String::new(); + for cause in err.chain() { + chained_cause.push_str(format!("{cause}; ").as_str()); + } + Self::Eyre(eyre::format_err!("{chained_cause}")) + } +} + /// The result of a deployment. #[derive(Debug)] pub struct DeployResult { diff --git a/crates/evm/fuzz/src/invariant/mod.rs b/crates/evm/fuzz/src/invariant/mod.rs index d6b3e574d..49f27e9f3 100644 --- a/crates/evm/fuzz/src/invariant/mod.rs +++ b/crates/evm/fuzz/src/invariant/mod.rs @@ -125,6 +125,18 @@ impl TargetedContracts { .filter(|(_, c)| !c.abi.functions.is_empty()) .flat_map(|(contract, c)| c.abi_fuzzed_functions().map(move |f| (contract, f))) } + + /// Identifies fuzzed contract and function based on given tx details and returns unique metric + /// key composed from contract identifier and function name. + pub fn fuzzed_metric_key(&self, tx: &BasicTxDetails) -> Option { + self.inner.get(&tx.call_details.target).and_then(|contract| { + contract + .abi + .functions() + .find(|f| f.selector() == tx.call_details.calldata[..4]) + .map(|function| format!("{}.{}", contract.identifier.clone(), function.name)) + }) + } } impl std::ops::Deref for TargetedContracts { diff --git a/crates/fmt/src/formatter.rs b/crates/fmt/src/formatter.rs index 02d62f705..6bb814e23 100644 --- a/crates/fmt/src/formatter.rs +++ b/crates/fmt/src/formatter.rs @@ -1628,7 +1628,8 @@ impl<'a, W: Write> Formatter<'a, W> { fmt.config.multiline_func_header, MultilineFuncHeaderStyle::ParamsFirst | MultilineFuncHeaderStyle::ParamsFirstMulti | - MultilineFuncHeaderStyle::All + MultilineFuncHeaderStyle::All | + MultilineFuncHeaderStyle::AllParams ); params_multiline = should_multiline || multiline || @@ -1637,13 +1638,17 @@ impl<'a, W: Write> Formatter<'a, W> { ¶ms, ",", )?; - // Write new line if we have only one parameter and params first set. - if params.len() == 1 && + // Write new line if we have only one parameter and params first set, + // or if the function definition is multiline and all params set. + let single_param_multiline = matches!( + fmt.config.multiline_func_header, + MultilineFuncHeaderStyle::ParamsFirst + ) || params_multiline && matches!( fmt.config.multiline_func_header, - MultilineFuncHeaderStyle::ParamsFirst - ) - { + MultilineFuncHeaderStyle::AllParams + ); + if params.len() == 1 && single_param_multiline { writeln!(fmt.buf())?; } fmt.write_chunks_separated(¶ms, ",", params_multiline)?; @@ -1736,7 +1741,10 @@ impl<'a, W: Write> Formatter<'a, W> { let should_multiline = header_multiline && if params_multiline { - matches!(self.config.multiline_func_header, MultilineFuncHeaderStyle::All) + matches!( + self.config.multiline_func_header, + MultilineFuncHeaderStyle::All | MultilineFuncHeaderStyle::AllParams + ) } else { matches!( self.config.multiline_func_header, diff --git a/crates/fmt/testdata/FunctionDefinition/all-params.fmt.sol b/crates/fmt/testdata/FunctionDefinition/all-params.fmt.sol new file mode 100644 index 000000000..db7164d28 --- /dev/null +++ b/crates/fmt/testdata/FunctionDefinition/all-params.fmt.sol @@ -0,0 +1,732 @@ +// config: line_length = 60 +// config: multiline_func_header = "all_params" +interface FunctionInterfaces { + function noParamsNoModifiersNoReturns(); + + function oneParam(uint256 x); + + function oneModifier() modifier1; + + function oneReturn() returns (uint256 y1); + + // function prefix + function withComments( // function name postfix + // x1 prefix + uint256 x1, // x1 postfix + // x2 prefix + uint256 x2, // x2 postfix + // x2 postfix2 + /* + multi-line x3 prefix + */ + uint256 x3 // x3 postfix + ) + // public prefix + public // public postfix + // pure prefix + pure // pure postfix + // modifier1 prefix + modifier1 // modifier1 postfix + // modifier2 prefix + modifier2 /* + mutliline modifier2 postfix + */ + // modifier3 prefix + modifier3 // modifier3 postfix + returns ( + // y1 prefix + uint256 y1, // y1 postfix + // y2 prefix + uint256 y2, // y2 postfix + // y3 prefix + uint256 y3 + ); // y3 postfix + // function postfix + + /*////////////////////////////////////////////////////////////////////////// + TEST + //////////////////////////////////////////////////////////////////////////*/ + function manyParams( + uint256 x1, + uint256 x2, + uint256 x3, + uint256 x4, + uint256 x5, + uint256 x6, + uint256 x7, + uint256 x8, + uint256 x9, + uint256 x10 + ); + + function manyModifiers() + modifier1 + modifier2 + modifier3 + modifier4 + modifier5 + modifier6 + modifier7 + modifier8 + modifier9 + modifier10; + + function manyReturns() + returns ( + uint256 y1, + uint256 y2, + uint256 y3, + uint256 y4, + uint256 y5, + uint256 y6, + uint256 y7, + uint256 y8, + uint256 y9, + uint256 y10 + ); + + function someParamsSomeModifiers( + uint256 x1, + uint256 x2, + uint256 x3 + ) + modifier1 + modifier2 + modifier3; + + function someParamsSomeReturns( + uint256 x1, + uint256 x2, + uint256 x3 + ) + returns (uint256 y1, uint256 y2, uint256 y3); + + function someModifiersSomeReturns() + modifier1 + modifier2 + modifier3 + returns (uint256 y1, uint256 y2, uint256 y3); + + function someParamSomeModifiersSomeReturns( + uint256 x1, + uint256 x2, + uint256 x3 + ) + modifier1 + modifier2 + modifier3 + returns (uint256 y1, uint256 y2, uint256 y3); + + function someParamsManyModifiers( + uint256 x1, + uint256 x2, + uint256 x3 + ) + modifier1 + modifier2 + modifier3 + modifier4 + modifier5 + modifier6 + modifier7 + modifier8 + modifier9 + modifier10; + + function someParamsManyReturns( + uint256 x1, + uint256 x2, + uint256 x3 + ) + returns ( + uint256 y1, + uint256 y2, + uint256 y3, + uint256 y4, + uint256 y5, + uint256 y6, + uint256 y7, + uint256 y8, + uint256 y9, + uint256 y10 + ); + + function manyParamsSomeModifiers( + uint256 x1, + uint256 x2, + uint256 x3, + uint256 x4, + uint256 x5, + uint256 x6, + uint256 x7, + uint256 x8, + uint256 x9, + uint256 x10 + ) + modifier1 + modifier2 + modifier3; + + function manyParamsSomeReturns( + uint256 x1, + uint256 x2, + uint256 x3, + uint256 x4, + uint256 x5, + uint256 x6, + uint256 x7, + uint256 x8, + uint256 x9, + uint256 x10 + ) + returns (uint256 y1, uint256 y2, uint256 y3); + + function manyParamsManyModifiers( + uint256 x1, + uint256 x2, + uint256 x3, + uint256 x4, + uint256 x5, + uint256 x6, + uint256 x7, + uint256 x8, + uint256 x9, + uint256 x10 + ) + modifier1 + modifier2 + modifier3 + modifier4 + modifier5 + modifier6 + modifier7 + modifier8 + modifier9 + modifier10; + + function manyParamsManyReturns( + uint256 x1, + uint256 x2, + uint256 x3, + uint256 x4, + uint256 x5, + uint256 x6, + uint256 x7, + uint256 x8, + uint256 x9, + uint256 x10 + ) + returns ( + uint256 y1, + uint256 y2, + uint256 y3, + uint256 y4, + uint256 y5, + uint256 y6, + uint256 y7, + uint256 y8, + uint256 y9, + uint256 y10 + ); + + function manyParamsManyModifiersManyReturns( + uint256 x1, + uint256 x2, + uint256 x3, + uint256 x4, + uint256 x5, + uint256 x6, + uint256 x7, + uint256 x8, + uint256 x9, + uint256 x10 + ) + modifier1 + modifier2 + modifier3 + modifier4 + modifier5 + modifier6 + modifier7 + modifier8 + modifier9 + modifier10 + returns ( + uint256 y1, + uint256 y2, + uint256 y3, + uint256 y4, + uint256 y5, + uint256 y6, + uint256 y7, + uint256 y8, + uint256 y9, + uint256 y10 + ); + + function modifierOrderCorrect01() + public + view + virtual + override + modifier1 + modifier2 + returns (uint256); + + function modifierOrderCorrect02() + private + pure + virtual + modifier1 + modifier2 + returns (string); + + function modifierOrderCorrect03() + external + payable + override + modifier1 + modifier2 + returns (address); + + function modifierOrderCorrect04() + internal + virtual + override + modifier1 + modifier2 + returns (uint256); + + function modifierOrderIncorrect01() + public + view + virtual + override + modifier1 + modifier2 + returns (uint256); + + function modifierOrderIncorrect02() + external + virtual + override + modifier1 + modifier2 + returns (uint256); + + function modifierOrderIncorrect03() + internal + pure + virtual + modifier1 + modifier2 + returns (uint256); + + function modifierOrderIncorrect04() + external + payable + override + modifier1 + modifier2 + returns (uint256); +} + +contract FunctionDefinitions { + function() external {} + fallback() external {} + + function() external payable {} + fallback() external payable {} + receive() external payable {} + + function noParamsNoModifiersNoReturns() { + a = 1; + } + + function oneParam(uint256 x) { + a = 1; + } + + function oneModifier() modifier1 { + a = 1; + } + + function oneReturn() returns (uint256 y1) { + a = 1; + } + + function manyParams( + uint256 x1, + uint256 x2, + uint256 x3, + uint256 x4, + uint256 x5, + uint256 x6, + uint256 x7, + uint256 x8, + uint256 x9, + uint256 x10 + ) { + a = 1; + } + + function manyModifiers() + modifier1 + modifier2 + modifier3 + modifier4 + modifier5 + modifier6 + modifier7 + modifier8 + modifier9 + modifier10 + { + a = 1; + } + + function manyReturns() + returns ( + uint256 y1, + uint256 y2, + uint256 y3, + uint256 y4, + uint256 y5, + uint256 y6, + uint256 y7, + uint256 y8, + uint256 y9, + uint256 y10 + ) + { + a = 1; + } + + function someParamsSomeModifiers( + uint256 x1, + uint256 x2, + uint256 x3 + ) + modifier1 + modifier2 + modifier3 + { + a = 1; + } + + function someParamsSomeReturns( + uint256 x1, + uint256 x2, + uint256 x3 + ) + returns (uint256 y1, uint256 y2, uint256 y3) + { + a = 1; + } + + function someModifiersSomeReturns() + modifier1 + modifier2 + modifier3 + returns (uint256 y1, uint256 y2, uint256 y3) + { + a = 1; + } + + function someParamSomeModifiersSomeReturns( + uint256 x1, + uint256 x2, + uint256 x3 + ) + modifier1 + modifier2 + modifier3 + returns (uint256 y1, uint256 y2, uint256 y3) + { + a = 1; + } + + function someParamsManyModifiers( + uint256 x1, + uint256 x2, + uint256 x3 + ) + modifier1 + modifier2 + modifier3 + modifier4 + modifier5 + modifier6 + modifier7 + modifier8 + modifier9 + modifier10 + { + a = 1; + } + + function someParamsManyReturns( + uint256 x1, + uint256 x2, + uint256 x3 + ) + returns ( + uint256 y1, + uint256 y2, + uint256 y3, + uint256 y4, + uint256 y5, + uint256 y6, + uint256 y7, + uint256 y8, + uint256 y9, + uint256 y10 + ) + { + a = 1; + } + + function manyParamsSomeModifiers( + uint256 x1, + uint256 x2, + uint256 x3, + uint256 x4, + uint256 x5, + uint256 x6, + uint256 x7, + uint256 x8, + uint256 x9, + uint256 x10 + ) + modifier1 + modifier2 + modifier3 + { + a = 1; + } + + function manyParamsSomeReturns( + uint256 x1, + uint256 x2, + uint256 x3, + uint256 x4, + uint256 x5, + uint256 x6, + uint256 x7, + uint256 x8, + uint256 x9, + uint256 x10 + ) + returns (uint256 y1, uint256 y2, uint256 y3) + { + a = 1; + } + + function manyParamsManyModifiers( + uint256 x1, + uint256 x2, + uint256 x3, + uint256 x4, + uint256 x5, + uint256 x6, + uint256 x7, + uint256 x8, + uint256 x9, + uint256 x10 + ) + public + modifier1 + modifier2 + modifier3 + modifier4 + modifier5 + modifier6 + modifier7 + modifier8 + modifier9 + modifier10 + { + a = 1; + } + + function manyParamsManyReturns( + uint256 x1, + uint256 x2, + uint256 x3, + uint256 x4, + uint256 x5, + uint256 x6, + uint256 x7, + uint256 x8, + uint256 x9, + uint256 x10 + ) + returns ( + uint256 y1, + uint256 y2, + uint256 y3, + uint256 y4, + uint256 y5, + uint256 y6, + uint256 y7, + uint256 y8, + uint256 y9, + uint256 y10 + ) + { + a = 1; + } + + function manyParamsManyModifiersManyReturns( + uint256 x1, + uint256 x2, + uint256 x3, + uint256 x4, + uint256 x5, + uint256 x6, + uint256 x7, + uint256 x8, + uint256 x9, + uint256 x10 + ) + modifier1 + modifier2 + modifier3 + modifier4 + modifier5 + modifier6 + modifier7 + modifier8 + modifier9 + modifier10 + returns ( + uint256 y1, + uint256 y2, + uint256 y3, + uint256 y4, + uint256 y5, + uint256 y6, + uint256 y7, + uint256 y8, + uint256 y9, + uint256 y10 + ) + { + a = 1; + } + + function modifierOrderCorrect01() + public + view + virtual + override + modifier1 + modifier2 + returns (uint256) + { + a = 1; + } + + function modifierOrderCorrect02() + private + pure + virtual + modifier1 + modifier2 + returns (string) + { + a = 1; + } + + function modifierOrderCorrect03() + external + payable + override + modifier1 + modifier2 + returns (address) + { + a = 1; + } + + function modifierOrderCorrect04() + internal + virtual + override + modifier1 + modifier2 + returns (uint256) + { + a = 1; + } + + function modifierOrderIncorrect01() + public + view + virtual + override + modifier1 + modifier2 + returns (uint256) + { + a = 1; + } + + function modifierOrderIncorrect02() + external + virtual + override + modifier1 + modifier2 + returns (uint256) + { + a = 1; + } + + function modifierOrderIncorrect03() + internal + pure + virtual + modifier1 + modifier2 + returns (uint256) + { + a = 1; + } + + function modifierOrderIncorrect04() + external + payable + override + modifier1 + modifier2 + returns (uint256) + { + a = 1; + } + + fallback() external payable virtual {} + receive() external payable virtual {} +} + +contract FunctionOverrides is + FunctionInterfaces, + FunctionDefinitions +{ + function noParamsNoModifiersNoReturns() override { + a = 1; + } + + function oneParam( + uint256 x + ) + override( + FunctionInterfaces, + FunctionDefinitions, + SomeOtherFunctionContract, + SomeImport.AndAnotherFunctionContract + ) + { + a = 1; + } +} diff --git a/crates/forge/Cargo.toml b/crates/forge/Cargo.toml index fa6b5ad55..e33301e65 100644 --- a/crates/forge/Cargo.toml +++ b/crates/forge/Cargo.toml @@ -37,6 +37,7 @@ foundry-wallets.workspace = true foundry-linking.workspace = true foundry-zksync-core.workspace = true foundry-zksync-compiler.workspace = true +forge-script-sequence.workspace = true ethers-contract-abigen = { workspace = true, features = ["providers"] } diff --git a/crates/forge/bin/cmd/bind.rs b/crates/forge/bin/cmd/bind.rs index d8739b42d..ec6b13dfd 100644 --- a/crates/forge/bin/cmd/bind.rs +++ b/crates/forge/bin/cmd/bind.rs @@ -106,10 +106,9 @@ impl BindArgs { } if self.ethers { - eprintln!( - "Warning: `--ethers` bindings are deprecated and will be removed in the future. \ - Consider using `--alloy` (default) instead." - ); + sh_warn!( + "`--ethers` bindings are deprecated and will be removed in the future. Consider using `--alloy` (default) instead." + )?; } let config = self.try_load_config_emit_warnings()?; @@ -118,7 +117,7 @@ impl BindArgs { if bindings_root.exists() { if !self.overwrite { - println!("Bindings found. Checking for consistency."); + sh_println!("Bindings found. Checking for consistency.")?; return self.check_existing_bindings(&artifacts, &bindings_root); } @@ -128,7 +127,7 @@ impl BindArgs { self.generate_bindings(&artifacts, &bindings_root)?; - println!("Bindings have been generated to {}", bindings_root.display()); + sh_println!("Bindings have been generated to {}", bindings_root.display())?; Ok(()) } @@ -274,7 +273,7 @@ impl BindArgs { fn check_ethers(&self, artifacts: &Path, bindings_root: &Path) -> Result<()> { let bindings = self.get_multi(artifacts)?.build()?; - println!("Checking bindings for {} contracts.", bindings.len()); + sh_println!("Checking bindings for {} contracts.", bindings.len())?; if !self.module { bindings .ensure_consistent_crate( @@ -294,14 +293,14 @@ impl BindArgs { } else { bindings.ensure_consistent_module(bindings_root, self.single_file)?; } - println!("OK."); + sh_println!("OK.")?; Ok(()) } fn check_alloy(&self, artifacts: &Path, bindings_root: &Path) -> Result<()> { let mut bindings = self.get_solmacrogen(artifacts)?; bindings.generate_bindings()?; - println!("Checking bindings for {} contracts", bindings.instances.len()); + sh_println!("Checking bindings for {} contracts", bindings.instances.len())?; bindings.check_consistency( &self.crate_name, &self.crate_version, @@ -311,7 +310,7 @@ impl BindArgs { self.module, self.alloy_version.clone(), )?; - println!("OK."); + sh_println!("OK.")?; Ok(()) } @@ -326,7 +325,7 @@ impl BindArgs { fn generate_ethers(&self, artifacts: &Path, bindings_root: &Path) -> Result<()> { let mut bindings = self.get_multi(artifacts)?.build()?; - println!("Generating bindings for {} contracts", bindings.len()); + sh_println!("Generating bindings for {} contracts", bindings.len())?; if !self.module { trace!(single_file = self.single_file, "generating crate"); if !self.skip_extra_derives { @@ -346,7 +345,7 @@ impl BindArgs { fn generate_alloy(&self, artifacts: &Path, bindings_root: &Path) -> Result<()> { let mut solmacrogen = self.get_solmacrogen(artifacts)?; - println!("Generating bindings for {} contracts", solmacrogen.instances.len()); + sh_println!("Generating bindings for {} contracts", solmacrogen.instances.len())?; if !self.module { trace!(single_file = self.single_file, "generating crate"); diff --git a/crates/forge/bin/cmd/bind_json.rs b/crates/forge/bin/cmd/bind_json.rs index 2736325a7..c6a052836 100644 --- a/crates/forge/bin/cmd/bind_json.rs +++ b/crates/forge/bin/cmd/bind_json.rs @@ -439,7 +439,7 @@ impl ResolvedState { } fs::write(&self.target_path, &result)?; - println!("Bindings written to {}", self.target_path.display()); + sh_println!("Bindings written to {}", self.target_path.display())?; Ok(result) } diff --git a/crates/forge/bin/cmd/build.rs b/crates/forge/bin/cmd/build.rs index e4658a457..60198758a 100644 --- a/crates/forge/bin/cmd/build.rs +++ b/crates/forge/bin/cmd/build.rs @@ -2,7 +2,7 @@ use super::{install, watch::WatchArgs}; use clap::Parser; use eyre::Result; use foundry_cli::{opts::CoreBuildArgs, utils::LoadConfig}; -use foundry_common::compile::ProjectCompiler; +use foundry_common::{compile::ProjectCompiler, shell}; use foundry_compilers::{ compilers::{multi::MultiCompilerLanguage, Language}, utils::source_files_iter, @@ -56,10 +56,16 @@ pub struct BuildArgs { pub names: bool, /// Print compiled contract sizes. + /// Constructor argument length is not included in the calculation of initcode size. #[arg(long)] #[serde(skip)] pub sizes: bool, + /// Ignore initcode contract bytecode size limit introduced by EIP-3860. + #[arg(long, alias = "ignore-initcode-size")] + #[serde(skip)] + pub ignore_eip_3860: bool, + #[command(flatten)] #[serde(flatten)] pub args: CoreBuildArgs, @@ -67,21 +73,15 @@ pub struct BuildArgs { #[command(flatten)] #[serde(skip)] pub watch: WatchArgs, - - /// Output the compilation errors in the json format. - /// This is useful when you want to use the output in other tools. - #[arg(long, conflicts_with = "silent")] - #[serde(skip)] - pub format_json: bool, } impl BuildArgs { + // TODO(zk): We cannot return `ProjectCompileOutput` as there's currently no way to return + // a common type from solc and zksolc branches. pub fn run(self) -> Result<()> { let mut config = self.try_load_config_emit_warnings()?; - if install::install_missing_dependencies(&mut config, self.args.silent) && - config.auto_detect_remappings - { + if install::install_missing_dependencies(&mut config) && config.auto_detect_remappings { // need to re-configure here to also catch additional remappings config = self.load_config(); } @@ -100,34 +100,46 @@ impl BuildArgs { } } + let format_json = shell::is_json(); let compiler = ProjectCompiler::new() + .files(files) .print_names(self.names) .print_sizes(self.sizes) - .quiet(self.format_json) - .bail(!self.format_json); + .ignore_eip_3860(self.ignore_eip_3860) + .quiet(format_json) + .bail(!format_json); let output = compiler.compile(&project)?; - if self.format_json { - println!("{}", serde_json::to_string_pretty(&output.output())?); + + if format_json { + sh_println!("{}", serde_json::to_string_pretty(&output.output())?)?; } + + // NOTE(zk): We skip returning output because currently there's no way to return from + // this function due to differing solc and zksolc project output types, and + // no way to return a default from either branch. Ok(output) + Ok(()) } else { + let format_json = shell::is_json(); let zk_project = foundry_zksync_compiler::config_create_project(&config, config.cache, false)?; let zk_compiler = ProjectCompiler::new() .print_names(self.names) .print_sizes(self.sizes) .zksync_sizes() - .quiet(self.format_json) - .bail(!self.format_json); + .quiet(format_json) + .bail(!format_json); let zk_output = zk_compiler.zksync_compile(&zk_project, config.zksync.avoid_contracts())?; - if self.format_json { + if format_json { println!("{}", serde_json::to_string_pretty(&zk_output.output())?); } - } - Ok(()) + // TODO(zk): We cannot return the zk_output as it does not match the concrete type for + // solc output. This is safe currently as the output is simply dropped. + Ok(()) + } } /// Returns the `Project` for the current workspace @@ -147,10 +159,12 @@ impl BuildArgs { /// Returns the [`watchexec::InitConfig`] and [`watchexec::RuntimeConfig`] necessary to /// bootstrap a new [`watchexe::Watchexec`] loop. pub(crate) fn watchexec_config(&self) -> Result { - // use the path arguments or if none where provided the `src` dir + // Use the path arguments or if none where provided the `src`, `test` and `script` + // directories as well as the `foundry.toml` configuration file. self.watch.watchexec_config(|| { let config = Config::from(self); - [config.src, config.test, config.script] + let foundry_toml: PathBuf = config.root.0.join(Config::FILE_NAME); + [config.src, config.test, config.script, foundry_toml] }) } } @@ -174,36 +188,10 @@ impl Provider for BuildArgs { dict.insert("sizes".to_string(), true.into()); } - Ok(Map::from([(Config::selected_profile(), dict)])) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use foundry_config::filter::SkipBuildFilter; - - #[test] - fn can_parse_build_filters() { - let args: BuildArgs = BuildArgs::parse_from(["foundry-cli", "--skip", "tests"]); - assert_eq!(args.args.skip, Some(vec![SkipBuildFilter::Tests])); - - let args: BuildArgs = BuildArgs::parse_from(["foundry-cli", "--skip", "scripts"]); - assert_eq!(args.args.skip, Some(vec![SkipBuildFilter::Scripts])); - - let args: BuildArgs = - BuildArgs::parse_from(["foundry-cli", "--skip", "tests", "--skip", "scripts"]); - assert_eq!(args.args.skip, Some(vec![SkipBuildFilter::Tests, SkipBuildFilter::Scripts])); - - let args: BuildArgs = BuildArgs::parse_from(["foundry-cli", "--skip", "tests", "scripts"]); - assert_eq!(args.args.skip, Some(vec![SkipBuildFilter::Tests, SkipBuildFilter::Scripts])); - } + if self.ignore_eip_3860 { + dict.insert("ignore_eip_3860".to_string(), true.into()); + } - #[test] - fn check_conflicts() { - let args: std::result::Result = - BuildArgs::try_parse_from(["foundry-cli", "--format-json", "--silent"]); - assert!(args.is_err()); - assert!(args.unwrap_err().kind() == clap::error::ErrorKind::ArgumentConflict); + Ok(Map::from([(Config::selected_profile(), dict)])) } } diff --git a/crates/forge/bin/cmd/cache.rs b/crates/forge/bin/cmd/cache.rs index 1adaf4d26..efbdde5cb 100644 --- a/crates/forge/bin/cmd/cache.rs +++ b/crates/forge/bin/cmd/cache.rs @@ -101,7 +101,7 @@ impl LsArgs { ChainOrAll::All => cache = Config::list_foundry_cache()?, } } - print!("{cache}"); + sh_print!("{cache}")?; Ok(()) } } diff --git a/crates/forge/bin/cmd/clone.rs b/crates/forge/bin/cmd/clone.rs index b71c5d3c5..a77615cf2 100644 --- a/crates/forge/bin/cmd/clone.rs +++ b/crates/forge/bin/cmd/clone.rs @@ -7,7 +7,7 @@ use foundry_block_explorers::{ errors::EtherscanError, Client, }; -use foundry_cli::{opts::EtherscanOpts, p_println, utils::Git}; +use foundry_cli::{opts::EtherscanOpts, utils::Git}; use foundry_common::{compile::ProjectCompiler, fs}; use foundry_compilers::{ artifacts::{ @@ -102,7 +102,8 @@ impl CloneArgs { let client = Client::new(chain, etherscan_api_key.clone())?; // step 1. get the metadata from client - p_println!(!opts.quiet => "Downloading the source code of {} from Etherscan...", address); + sh_println!("Downloading the source code of {address} from Etherscan...")?; + let meta = Self::collect_metadata_from_client(address, &client).await?; // step 2. initialize an empty project @@ -117,17 +118,17 @@ impl CloneArgs { // step 4. collect the compilation metadata // if the etherscan api key is not set, we need to wait for 3 seconds between calls - p_println!(!opts.quiet => "Collecting the creation information of {} from Etherscan...", address); + sh_println!("Collecting the creation information of {address} from Etherscan...")?; + if etherscan_api_key.is_empty() { - p_println!(!opts.quiet => "Waiting for 5 seconds to avoid rate limit..."); + sh_warn!("Waiting for 5 seconds to avoid rate limit...")?; tokio::time::sleep(Duration::from_secs(5)).await; } - Self::collect_compilation_metadata(&meta, chain, address, &root, &client, opts.quiet) - .await?; + Self::collect_compilation_metadata(&meta, chain, address, &root, &client).await?; // step 5. git add and commit the changes if needed if !opts.no_commit { - let git = Git::new(&root).quiet(opts.quiet); + let git = Git::new(&root); git.add(Some("--all"))?; let msg = format!("chore: forge clone {address}"); git.commit(&msg)?; @@ -185,10 +186,9 @@ impl CloneArgs { address: Address, root: &PathBuf, client: &C, - quiet: bool, ) -> Result<()> { // compile the cloned contract - let compile_output = compile_project(root, quiet)?; + let compile_output = compile_project(root)?; let (main_file, main_artifact) = find_main_contract(&compile_output, &meta.contract_name)?; let main_file = main_file.strip_prefix(root)?.to_path_buf(); let storage_layout = @@ -547,11 +547,11 @@ fn dump_sources(meta: &Metadata, root: &PathBuf, no_reorg: bool) -> Result Result { +pub fn compile_project(root: &Path) -> Result { let mut config = Config::load_with_root(root).sanitized(); config.extra_output.push(ContractOutputSelection::StorageLayout); let project = config.project()?; - let compiler = ProjectCompiler::new().quiet_if(quiet); + let compiler = ProjectCompiler::new(); compiler.compile(&project) } @@ -617,9 +617,10 @@ mod tests { use foundry_test_utils::rpc::next_mainnet_etherscan_api_key; use std::collections::BTreeMap; + #[allow(clippy::disallowed_macros)] fn assert_successful_compilation(root: &PathBuf) -> ProjectCompileOutput { println!("project_root: {root:#?}"); - compile_project(root, false).expect("compilation failure") + compile_project(root).expect("compilation failure") } fn assert_compilation_result( @@ -721,7 +722,6 @@ mod tests { address, &project_root, &client, - false, ) .await .unwrap(); diff --git a/crates/forge/bin/cmd/compiler.rs b/crates/forge/bin/cmd/compiler.rs new file mode 100644 index 000000000..0b0ec171b --- /dev/null +++ b/crates/forge/bin/cmd/compiler.rs @@ -0,0 +1,186 @@ +use clap::{ArgAction, Parser, Subcommand, ValueHint}; +use eyre::Result; +use foundry_compilers::{artifacts::EvmVersion, Graph}; +use foundry_config::Config; +use semver::Version; +use serde::Serialize; +use std::{collections::BTreeMap, path::PathBuf}; + +/// CLI arguments for `forge compiler`. +#[derive(Debug, Parser)] +pub struct CompilerArgs { + #[command(subcommand)] + pub sub: CompilerSubcommands, +} + +impl CompilerArgs { + pub fn run(self) -> Result<()> { + match self.sub { + CompilerSubcommands::Resolve(args) => args.run(), + } + } +} + +#[derive(Debug, Subcommand)] +pub enum CompilerSubcommands { + /// Retrieves the resolved version(s) of the compiler within the project. + #[command(visible_alias = "r")] + Resolve(ResolveArgs), +} + +/// Resolved compiler within the project. +#[derive(Serialize)] +struct ResolvedCompiler { + /// Compiler version. + version: Version, + /// Max supported EVM version of compiler. + #[serde(skip_serializing_if = "Option::is_none")] + evm_version: Option, + /// Source paths. + #[serde(skip_serializing_if = "Vec::is_empty")] + paths: Vec, +} + +/// CLI arguments for `forge compiler resolve`. +#[derive(Debug, Parser)] +pub struct ResolveArgs { + /// The root directory + #[arg(long, short, value_hint = ValueHint::DirPath, value_name = "PATH")] + root: Option, + + /// Skip files that match the given regex pattern. + #[arg(long, short, value_name = "REGEX")] + skip: Option, + + /// Verbosity of the output. + /// + /// Pass multiple times to increase the verbosity (e.g. -v, -vv, -vvv). + /// + /// Verbosity levels: + /// - 0: Print compiler versions. + /// - 1: Print compiler version and source paths. + /// - 2: Print compiler version, source paths and max supported EVM version of the compiler. + #[arg(long, short, verbatim_doc_comment, action = ArgAction::Count, help_heading = "Display options")] + pub verbosity: u8, + + /// Print as JSON. + #[arg(long, short, help_heading = "Display options")] + json: bool, +} + +impl ResolveArgs { + pub fn run(self) -> Result<()> { + let Self { root, skip, verbosity, json } = self; + + let root = root.unwrap_or_else(|| PathBuf::from(".")); + let config = Config::load_with_root(&root); + let project = config.project()?; + + let graph = Graph::resolve(&project.paths)?; + let (sources, _) = graph.into_sources_by_version( + project.offline, + &project.locked_versions, + &project.compiler, + )?; + + let mut output: BTreeMap> = BTreeMap::new(); + + for (language, sources) in sources { + let mut versions_with_paths: Vec = sources + .iter() + .map(|(version, sources)| { + let paths: Vec = sources + .iter() + .filter_map(|(path_file, _)| { + let path_str = path_file + .strip_prefix(&project.paths.root) + .unwrap_or(path_file) + .to_path_buf() + .display() + .to_string(); + + // Skip files that match the given regex pattern. + if let Some(ref regex) = skip { + if regex.is_match(&path_str) { + return None; + } + } + + Some(path_str) + }) + .collect(); + + let evm_version = if verbosity > 1 { + Some( + EvmVersion::default() + .normalize_version_solc(version) + .unwrap_or_default(), + ) + } else { + None + }; + + ResolvedCompiler { version: version.clone(), evm_version, paths } + }) + .filter(|version| !version.paths.is_empty()) + .collect(); + + // Sort by SemVer version. + versions_with_paths.sort_by(|v1, v2| Version::cmp(&v1.version, &v2.version)); + + // Skip language if no paths are found after filtering. + if !versions_with_paths.is_empty() { + // Clear paths if verbosity is 0, performed only after filtering to avoid being + // skipped. + if verbosity == 0 { + versions_with_paths.iter_mut().for_each(|version| version.paths.clear()); + } + + output.insert(language.to_string(), versions_with_paths); + } + } + + if json { + sh_println!("{}", serde_json::to_string(&output)?)?; + return Ok(()); + } + + for (language, compilers) in &output { + match verbosity { + 0 => sh_println!("{language}:")?, + _ => sh_println!("{language}:\n")?, + } + + for resolved_compiler in compilers { + let version = &resolved_compiler.version; + match verbosity { + 0 => sh_println!("- {version}")?, + _ => { + if let Some(evm) = &resolved_compiler.evm_version { + sh_println!("{version} (<= {evm}):")? + } else { + sh_println!("{version}:")? + } + } + } + + if verbosity > 0 { + let paths = &resolved_compiler.paths; + for (idx, path) in paths.iter().enumerate() { + if idx == paths.len() - 1 { + sh_println!("└── {path}\n")? + } else { + sh_println!("├── {path}")? + } + } + } + } + + if verbosity == 0 { + sh_println!()? + } + } + + Ok(()) + } +} diff --git a/crates/forge/bin/cmd/config.rs b/crates/forge/bin/cmd/config.rs index fc325e39d..652c5a10f 100644 --- a/crates/forge/bin/cmd/config.rs +++ b/crates/forge/bin/cmd/config.rs @@ -2,7 +2,7 @@ use super::build::BuildArgs; use clap::Parser; use eyre::Result; use foundry_cli::utils::LoadConfig; -use foundry_common::{evm::EvmArgs, term::cli_warn}; +use foundry_common::evm::EvmArgs; use foundry_config::fix::fix_tomls; foundry_config::impl_figment_convert!(ConfigArgs, opts, evm_opts); @@ -34,7 +34,7 @@ impl ConfigArgs { pub fn run(self) -> Result<()> { if self.fix { for warning in fix_tomls() { - cli_warn!("{warning}"); + sh_warn!("{warning}")?; } return Ok(()) } @@ -57,7 +57,7 @@ impl ConfigArgs { config.to_string_pretty()? }; - println!("{s}"); + sh_println!("{s}")?; Ok(()) } } diff --git a/crates/forge/bin/cmd/coverage.rs b/crates/forge/bin/cmd/coverage.rs index 17e4c088d..9cc8a69e6 100644 --- a/crates/forge/bin/cmd/coverage.rs +++ b/crates/forge/bin/cmd/coverage.rs @@ -13,10 +13,7 @@ use forge::{ utils::IcPcMap, MultiContractRunnerBuilder, TestOptions, }; -use foundry_cli::{ - p_println, - utils::{LoadConfig, STATIC_FUZZ_SEED}, -}; +use foundry_cli::utils::{LoadConfig, STATIC_FUZZ_SEED}; use foundry_common::{compile::ProjectCompiler, fs}; use foundry_compilers::{ artifacts::{sourcemap::SourceMap, CompactBytecode, CompactDeployedBytecode}, @@ -30,7 +27,6 @@ use std::{ path::{Path, PathBuf}, sync::Arc, }; -use yansi::Paint; // Loads project's figment and merges the build cli arguments into it foundry_config::impl_figment_convert!(CoverageArgs, test); @@ -75,9 +71,7 @@ impl CoverageArgs { let (mut config, evm_opts) = self.load_config_and_evm_opts_emit_warnings()?; // install missing dependencies - if install::install_missing_dependencies(&mut config, self.test.build_args().silent) && - config.auto_detect_remappings - { + if install::install_missing_dependencies(&mut config) && config.auto_detect_remappings { // need to re-configure here to also catch additional remappings config = self.load_config(); } @@ -89,10 +83,10 @@ impl CoverageArgs { config.ast = true; let (project, output) = self.build(&config)?; - p_println!(!self.test.build_args().silent => "Analysing contracts..."); + sh_println!("Analysing contracts...")?; let report = self.prepare(&project, &output)?; - p_println!(!self.test.build_args().silent => "Running tests..."); + sh_println!("Running tests...")?; self.collect(project, &output, report, Arc::new(config), evm_opts).await } @@ -113,14 +107,13 @@ impl CoverageArgs { } // print warning message - let msg = concat!( + sh_warn!("{}", concat!( "Warning! \"--ir-minimum\" flag enables viaIR with minimum optimization, \ which can result in inaccurate source mappings.\n", "Only use this flag as a workaround if you are experiencing \"stack too deep\" errors.\n", "Note that \"viaIR\" is only available in Solidity 0.8.13 and above.\n", "See more: https://github.com/foundry-rs/foundry/issues/3357", - ).yellow(); - p_println!(!self.test.build_args().silent => "{msg}"); + ))?; // Enable viaIR with minimum optimization // https://github.com/ethereum/solidity/issues/12533#issuecomment-1013073350 @@ -255,7 +248,7 @@ impl CoverageArgs { let outcome = self.test.run_tests(runner, config.clone(), verbosity, &filter, output).await?; - outcome.ensure_ok()?; + outcome.ensure_ok(false)?; // Add hit data to the coverage report let data = outcome.results.iter().flat_map(|(_, suite)| { diff --git a/crates/forge/bin/cmd/create.rs b/crates/forge/bin/cmd/create.rs index 9f0212ae7..0b3bf3e8a 100644 --- a/crates/forge/bin/cmd/create.rs +++ b/crates/forge/bin/cmd/create.rs @@ -18,6 +18,7 @@ use foundry_cli::{ use foundry_common::{ compile::{self, ProjectCompiler}, fmt::parse_tokens, + shell, }; use foundry_compilers::{ artifacts::BytecodeObject, info::ContractInfo, utils::canonicalize, @@ -59,6 +60,7 @@ pub struct CreateArgs { num_args(1..), conflicts_with = "constructor_args_path", value_name = "ARGS", + allow_hyphen_values = true, )] constructor_args: Vec, @@ -71,10 +73,6 @@ pub struct CreateArgs { )] constructor_args_path: Option, - /// Print the deployment information as JSON. - #[arg(long, help_heading = "Display options")] - json: bool, - /// Verify contract after creation. #[arg(long)] verify: bool, @@ -152,9 +150,7 @@ impl CreateArgs { let config = self.opts.try_load_config_emit_warnings()?; let zk_project = foundry_zksync_compiler::config_create_project(&config, config.cache, false)?; - let zk_compiler = ProjectCompiler::new() - .quiet(self.json || self.opts.silent) - .files([target_path.clone()]); + let zk_compiler = ProjectCompiler::new().files([target_path.clone()]); let mut zk_output = zk_compiler.zksync_compile(&zk_project, config.zksync.avoid_contracts())?; @@ -288,8 +284,7 @@ impl CreateArgs { project.find_contract_path(&self.contract.name)? }; - let mut output = - compile::compile_target(&target_path, &project, self.json || self.opts.silent)?; + let mut output = compile::compile_target(&target_path, &project, shell::is_json())?; let (abi, bin, _) = remove_contract(&mut output, &target_path, &self.contract.name)?; @@ -309,20 +304,19 @@ impl CreateArgs { }; // Add arguments to constructor - let provider = utils::get_provider(&config)?; - let params = match abi.constructor { - Some(ref v) => { - let constructor_args = - if let Some(ref constructor_args_path) = self.constructor_args_path { - read_constructor_args_file(constructor_args_path.to_path_buf())? - } else { - self.constructor_args.clone() - }; - self.parse_constructor_args(v, &constructor_args)? - } - None => vec![], + let params = if let Some(constructor) = &abi.constructor { + let constructor_args = + self.constructor_args_path.clone().map(read_constructor_args_file).transpose()?; + self.parse_constructor_args( + constructor, + constructor_args.as_deref().unwrap_or(&self.constructor_args), + )? + } else { + vec![] }; + let provider = utils::get_provider(&config)?; + // respect chain, if set explicitly via cmd args let chain_id = if let Some(chain_id) = self.chain_id() { chain_id @@ -501,24 +495,24 @@ impl CreateArgs { let (deployed_contract, receipt) = deployer.send_with_receipt().await?; let address = deployed_contract; - if self.json { + if shell::is_json() { let output = json!({ "deployer": deployer_address.to_string(), "deployedTo": address.to_string(), "transactionHash": receipt.transaction_hash }); - println!("{output}"); + sh_println!("{output}")?; } else { - println!("Deployer: {deployer_address}"); - println!("Deployed to: {address}"); - println!("Transaction hash: {:?}", receipt.transaction_hash); + sh_println!("Deployer: {deployer_address}")?; + sh_println!("Deployed to: {address}")?; + sh_println!("Transaction hash: {:?}", receipt.transaction_hash)?; }; if !self.verify { return Ok(()); } - println!("Starting contract verification..."); + sh_println!("Starting contract verification...")?; let num_of_optimizations = if self.opts.compiler.optimize.unwrap_or_default() { self.opts.compiler.optimizer_runs @@ -536,7 +530,7 @@ impl CreateArgs { rpc: Default::default(), flatten: false, force: false, - skip_is_verified_check: false, + skip_is_verified_check: true, watch: true, retry: self.retry, libraries: self.opts.libraries.clone(), @@ -651,7 +645,7 @@ impl CreateArgs { let (deployed_contract, receipt) = deployer.send_with_receipt_zk(zk_signer).await?; let address = deployed_contract; - if self.json { + if shell::is_json() { let output = json!({ "deployer": deployer_address.to_string(), "deployedTo": address.to_string(), @@ -698,7 +692,7 @@ impl CreateArgs { guess_constructor_args: false, zksync: true, }; - println!("Waiting for {} to detect contract deployment...", verify.verifier.verifier); + sh_println!("Waiting for {} to detect contract deployment...", verify.verifier.verifier)?; verify.run().await } @@ -1080,6 +1074,7 @@ impl From for ContractDeploymentError { #[cfg(test)] mod tests { use super::*; + use alloy_primitives::I256; #[test] fn can_parse_create() { @@ -1135,4 +1130,17 @@ mod tests { let constructor: Constructor = serde_json::from_str(r#"{"type":"constructor","inputs":[{"name":"_points","type":"tuple[]","internalType":"struct Point[]","components":[{"name":"x","type":"uint256","internalType":"uint256"},{"name":"y","type":"uint256","internalType":"uint256"}]}],"stateMutability":"nonpayable"}"#).unwrap(); let _params = args.parse_constructor_args(&constructor, &args.constructor_args).unwrap(); } + + #[test] + fn test_parse_int_constructor_args() { + let args: CreateArgs = CreateArgs::parse_from([ + "foundry-cli", + "src/Domains.sol:Domains", + "--constructor-args", + "-5", + ]); + let constructor: Constructor = serde_json::from_str(r#"{"type":"constructor","inputs":[{"name":"_name","type":"int256","internalType":"int256"}],"stateMutability":"nonpayable"}"#).unwrap(); + let params = args.parse_constructor_args(&constructor, &args.constructor_args).unwrap(); + assert_eq!(params, vec![DynSolValue::Int(I256::unchecked_from(-5), 256)]); + } } diff --git a/crates/forge/bin/cmd/debug.rs b/crates/forge/bin/cmd/debug.rs index 8fe1d2e32..421478bd5 100644 --- a/crates/forge/bin/cmd/debug.rs +++ b/crates/forge/bin/cmd/debug.rs @@ -33,6 +33,15 @@ pub struct DebugArgs { #[arg(long)] pub debug: bool, + /// File path to dump execution details as JSON. + #[arg( + long, + requires = "debug", + value_hint = ValueHint::FilePath, + value_name = "PATH" + )] + pub dump: Option, + #[command(flatten)] pub opts: CoreBuildArgs, @@ -51,6 +60,7 @@ impl DebugArgs { opts: self.opts, evm_opts: self.evm_opts, debug: true, + dump: self.dump, retry: RETRY_VERIFY_ON_CREATE, ..Default::default() }; diff --git a/crates/forge/bin/cmd/doc/server.rs b/crates/forge/bin/cmd/doc/server.rs index 72585a2bf..b42106d99 100644 --- a/crates/forge/bin/cmd/doc/server.rs +++ b/crates/forge/bin/cmd/doc/server.rs @@ -75,7 +75,7 @@ impl Server { let file_404 = get_404_output_file(&input_404); let serving_url = format!("http://{address}"); - println!("Serving on: {serving_url}"); + sh_println!("Serving on: {serving_url}")?; let thread_handle = std::thread::spawn(move || serve(build_dir, sockaddr, &file_404)); diff --git a/crates/forge/bin/cmd/eip712.rs b/crates/forge/bin/cmd/eip712.rs index e9ef88008..2c125b7d0 100644 --- a/crates/forge/bin/cmd/eip712.rs +++ b/crates/forge/bin/cmd/eip712.rs @@ -63,8 +63,7 @@ impl Eip712Args { for (id, _) in structs_in_target { if let Some(resolved) = resolver.resolve_struct_eip712(id)? { - println!("{resolved}"); - println!(); + sh_println!("{resolved}\n")?; } } diff --git a/crates/forge/bin/cmd/flatten.rs b/crates/forge/bin/cmd/flatten.rs index f538be5a8..7bbb0d1e2 100644 --- a/crates/forge/bin/cmd/flatten.rs +++ b/crates/forge/bin/cmd/flatten.rs @@ -64,9 +64,9 @@ impl FlattenArgs { Some(output) => { fs::create_dir_all(output.parent().unwrap())?; fs::write(&output, flattened)?; - println!("Flattened file written at {}", output.display()); + sh_println!("Flattened file written at {}", output.display())?; } - None => println!("{flattened}"), + None => sh_println!("{flattened}")?, }; Ok(()) diff --git a/crates/forge/bin/cmd/fmt.rs b/crates/forge/bin/cmd/fmt.rs index 9fd016ac7..49548e1b6 100644 --- a/crates/forge/bin/cmd/fmt.rs +++ b/crates/forge/bin/cmd/fmt.rs @@ -2,7 +2,7 @@ use clap::{Parser, ValueHint}; use eyre::{Context, Result}; use forge_fmt::{format_to, parse}; use foundry_cli::utils::{FoundryPathExt, LoadConfig}; -use foundry_common::{fs, term::cli_warn}; +use foundry_common::fs; use foundry_compilers::{compilers::solc::SolcLanguage, solc::SOLC_EXTENSIONS}; use foundry_config::{filter::expand_globs, impl_figment_convert_basic}; use rayon::prelude::*; @@ -111,7 +111,7 @@ impl FmtArgs { let mut lines = source[..loc.start().min(source.len())].split('\n'); let col = lines.next_back().unwrap().len() + 1; let row = lines.count() + 1; - cli_warn!("[{}:{}:{}] {}", name, row, col, warning); + sh_warn!("[{}:{}:{}] {}", name, row, col, warning)?; } } @@ -129,7 +129,7 @@ impl FmtArgs { let new_format = diff.ratio() < 1.0; if self.check || path.is_none() { if self.raw { - print!("{output}"); + sh_print!("{output}")?; } // If new format then compute diff summary. @@ -149,11 +149,11 @@ impl FmtArgs { Input::Stdin(source) => format(source, None).map(|diff| vec![diff]), Input::Paths(paths) => { if paths.is_empty() { - cli_warn!( + sh_warn!( "Nothing to format.\n\ HINT: If you are working outside of the project, \ try providing paths to your source files: `forge fmt `" - ); + )?; return Ok(()) } paths diff --git a/crates/forge/bin/cmd/geiger/mod.rs b/crates/forge/bin/cmd/geiger/mod.rs index da0397cc5..4167b7882 100644 --- a/crates/forge/bin/cmd/geiger/mod.rs +++ b/crates/forge/bin/cmd/geiger/mod.rs @@ -6,7 +6,6 @@ use foundry_config::{impl_figment_convert_basic, Config}; use itertools::Itertools; use rayon::prelude::*; use std::path::PathBuf; -use yansi::Paint; mod error; @@ -95,7 +94,7 @@ impl GeigerArgs { let sources = self.sources(&config).wrap_err("Failed to resolve files")?; if config.ffi { - eprintln!("{}\n", "ffi enabled".red()); + sh_warn!("FFI enabled\n")?; } let root = config.root.0; @@ -107,12 +106,12 @@ impl GeigerArgs { let len = metrics.cheatcodes.len(); let printer = SolFileMetricsPrinter { metrics: &metrics, root: &root }; if self.full || len == 0 { - eprint!("{printer}"); + let _ = sh_eprint!("{printer}"); } len } Err(err) => { - eprintln!("{err}"); + let _ = sh_err!("{err}"); 0 } }) diff --git a/crates/forge/bin/cmd/generate/mod.rs b/crates/forge/bin/cmd/generate/mod.rs index 2c3a51282..f1f69d838 100644 --- a/crates/forge/bin/cmd/generate/mod.rs +++ b/crates/forge/bin/cmd/generate/mod.rs @@ -44,7 +44,7 @@ impl GenerateTestArgs { // Write the test content to the test file. fs::write(&test_file_path, test_content)?; - println!("{} test file: {}", "Generated".green(), test_file_path.to_str().unwrap()); + sh_println!("{} test file: {}", "Generated".green(), test_file_path.to_str().unwrap())?; Ok(()) } } diff --git a/crates/forge/bin/cmd/init.rs b/crates/forge/bin/cmd/init.rs index 54d871158..94056c3db 100644 --- a/crates/forge/bin/cmd/init.rs +++ b/crates/forge/bin/cmd/init.rs @@ -1,7 +1,7 @@ use super::install::DependencyInstallOpts; use clap::{Parser, ValueHint}; use eyre::Result; -use foundry_cli::{p_println, utils::Git}; +use foundry_cli::utils::Git; use foundry_common::fs; use foundry_compilers::artifacts::remappings::Remapping; use foundry_config::Config; @@ -44,14 +44,14 @@ pub struct InitArgs { impl InitArgs { pub fn run(self) -> Result<()> { let Self { root, template, branch, opts, offline, force, vscode } = self; - let DependencyInstallOpts { shallow, no_git, no_commit, quiet, zksync } = opts; + let DependencyInstallOpts { shallow, no_git, no_commit, zksync } = opts; // create the root dir if it does not exist if !root.exists() { fs::create_dir_all(&root)?; } let root = dunce::canonicalize(root)?; - let git = Git::new(&root).quiet(quiet).shallow(shallow); + let git = Git::new(&root).shallow(shallow); // if a template is provided, then this command initializes a git repo, // fetches the template repo, and resets the git history to the head of the fetched @@ -62,7 +62,7 @@ impl InitArgs { } else { "https://github.com/".to_string() + &template }; - p_println!(!quiet => "Initializing {} from {}...", root.display(), template); + sh_println!("Initializing {} from {}...", root.display(), template)?; // initialize the git repository git.init()?; @@ -95,8 +95,7 @@ impl InitArgs { Run with the `--force` flag to initialize regardless." ); } - - p_println!(!quiet => "Target directory is not empty, but `--force` was specified"); + sh_warn!("Target directory is not empty, but `--force` was specified")?; } // ensure git status is clean before generating anything @@ -104,7 +103,7 @@ impl InitArgs { git.ensure_clean()?; } - p_println!(!quiet => "Initializing {}...", root.display()); + sh_println!("Initializing {}...", root.display())?; // make the dirs let src = root.join("src"); @@ -145,7 +144,7 @@ impl InitArgs { // install forge-std if !offline { if root.join("lib/forge-std").exists() { - p_println!(!quiet => "\"lib/forge-std\" already exists, skipping install...."); + sh_warn!("\"lib/forge-std\" already exists, skipping install...")?; self.opts.install(&mut config, vec![])?; } else { let dep = "https://github.com/foundry-rs/forge-std".parse()?; @@ -156,7 +155,7 @@ impl InitArgs { // install forge-zksync-std if zksync && !offline { if root.join("lib/forge-zksync-std").exists() { - p_println!(!quiet => "\"lib/forge-zksync-std\" already exists, skipping install...."); + sh_println!("\"lib/forge-zksync-std\" already exists, skipping install....")?; self.opts.install(&mut config, vec![])?; } else { let dep = "https://github.com/Moonsong-Labs/forge-zksync-std".parse()?; @@ -170,7 +169,7 @@ impl InitArgs { } } - p_println!(!quiet => " {} forge project", "Initialized".green()); + sh_println!("{}", " Initialized forge project".green())?; Ok(()) } } diff --git a/crates/forge/bin/cmd/inspect.rs b/crates/forge/bin/cmd/inspect.rs index 14d43d6f5..5c7c224f7 100644 --- a/crates/forge/bin/cmd/inspect.rs +++ b/crates/forge/bin/cmd/inspect.rs @@ -87,7 +87,7 @@ impl InspectArgs { .ok_or_else(|| eyre::eyre!("Failed to fetch lossless ABI"))?; if pretty { let source = foundry_cli::utils::abi_to_solidity(abi, &contract.name)?; - println!("{source}"); + sh_println!("{source}")?; } else { print_json(abi)?; } @@ -201,7 +201,7 @@ pub fn print_storage_layout(storage_layout: Option<&StorageLayout>, pretty: bool ]); } - println!("{table}"); + sh_println!("{table}")?; Ok(()) } @@ -390,12 +390,12 @@ impl ContractArtifactField { } fn print_json(obj: &impl serde::Serialize) -> Result<()> { - println!("{}", serde_json::to_string_pretty(obj)?); + sh_println!("{}", serde_json::to_string_pretty(obj)?)?; Ok(()) } fn print_json_str(obj: &impl serde::Serialize, key: Option<&str>) -> Result<()> { - println!("{}", get_json_str(obj, key)?); + sh_println!("{}", get_json_str(obj, key)?)?; Ok(()) } @@ -408,9 +408,9 @@ fn print_yul(yul: Option<&str>, pretty: bool) -> Result<()> { LazyLock::new(|| Regex::new(r"(///.*\n\s*)|(\s*/\*\*.*\*/)").unwrap()); if pretty { - println!("{}", YUL_COMMENTS.replace_all(yul, "")); + sh_println!("{}", YUL_COMMENTS.replace_all(yul, ""))?; } else { - println!("{yul}"); + sh_println!("{yul}")?; } Ok(()) @@ -450,7 +450,7 @@ fn print_eof(bytecode: Option) -> Result<()> { let eof = Eof::decode(bytecode).wrap_err("Failed to decode EOF")?; - println!("{}", pretty_eof(&eof)?); + sh_println!("{}", pretty_eof(&eof)?)?; Ok(()) } diff --git a/crates/forge/bin/cmd/install.rs b/crates/forge/bin/cmd/install.rs index 233d0b803..ca5608ca3 100644 --- a/crates/forge/bin/cmd/install.rs +++ b/crates/forge/bin/cmd/install.rs @@ -2,7 +2,6 @@ use clap::{Parser, ValueHint}; use eyre::{Context, Result}; use foundry_cli::{ opts::Dependency, - p_println, prompt, utils::{CommandUtils, Git, LoadConfig}, }; use foundry_common::fs; @@ -38,6 +37,8 @@ pub struct InstallArgs { /// - A tag: v1.2.3 /// - A commit: 8e8128 /// + /// For exact match, a ref can be provided with `@tag=`, `@branch=` or `@rev=` prefix. + /// /// Target installation directory can be added via `=` suffix. /// The dependency will installed to `lib/`. dependencies: Vec, @@ -78,10 +79,6 @@ pub struct DependencyInstallOpts { #[arg(long)] pub no_commit: bool, - /// Do not print any messages. - #[arg(short, long)] - pub quiet: bool, - /// Install ZKsync specific libraries. #[arg(long)] pub zksync: bool, @@ -89,7 +86,7 @@ pub struct DependencyInstallOpts { impl DependencyInstallOpts { pub fn git(self, config: &Config) -> Git<'_> { - Git::from_config(config).quiet(self.quiet).shallow(self.shallow) + Git::from_config(config).shallow(self.shallow) } /// Installs all missing dependencies. @@ -98,17 +95,16 @@ impl DependencyInstallOpts { /// /// Returns true if any dependency was installed. pub fn install_missing_dependencies(mut self, config: &mut Config) -> bool { - let Self { quiet, .. } = self; let lib = config.install_lib_dir(); if self.git(config).has_missing_dependencies(Some(lib)).unwrap_or(false) { // The extra newline is needed, otherwise the compiler output will overwrite the message - p_println!(!quiet => "Missing dependencies found. Installing now...\n"); + let _ = sh_println!("Missing dependencies found. Installing now...\n"); self.no_commit = true; - if self.install(config, Vec::new()).is_err() && !quiet { - eprintln!( + if self.install(config, Vec::new()).is_err() { + let _ = sh_warn!( "{}", - "Your project has missing dependencies that could not be installed.".yellow() - ) + "Your project has missing dependencies that could not be installed." + ); } true } else { @@ -118,7 +114,7 @@ impl DependencyInstallOpts { /// Installs all dependencies pub fn install(self, config: &mut Config, dependencies: Vec) -> Result<()> { - let Self { no_git, no_commit, quiet, .. } = self; + let Self { no_git, no_commit, .. } = self; let git = self.git(config); @@ -130,7 +126,8 @@ impl DependencyInstallOpts { let root = Git::root_of(git.root)?; match git.has_submodules(Some(&root)) { Ok(true) => { - p_println!(!quiet => "Updating dependencies in {}", libs.display()); + sh_println!("Updating dependencies in {}", libs.display())?; + // recursively fetch all submodules (without fetching latest) git.submodule_update(false, false, false, true, Some(&libs))?; } @@ -152,7 +149,13 @@ impl DependencyInstallOpts { let rel_path = path .strip_prefix(git.root) .wrap_err("Library directory is not relative to the repository root")?; - p_println!(!quiet => "Installing {} in {} (url: {:?}, tag: {:?})", dep.name, path.display(), dep.url, dep.tag); + sh_println!( + "Installing {} in {} (url: {:?}, tag: {:?})", + dep.name, + path.display(), + dep.url, + dep.tag + )?; // this tracks the actual installed tag let installed_tag; @@ -194,14 +197,12 @@ impl DependencyInstallOpts { } } - if !quiet { - let mut msg = format!(" {} {}", "Installed".green(), dep.name); - if let Some(tag) = dep.tag.or(installed_tag) { - msg.push(' '); - msg.push_str(tag.as_str()); - } - println!("{msg}"); + let mut msg = format!(" {} {}", "Installed".green(), dep.name); + if let Some(tag) = dep.tag.or(installed_tag) { + msg.push(' '); + msg.push_str(tag.as_str()); } + sh_println!("{msg}")?; } // update `libs` in config if not included yet @@ -213,8 +214,8 @@ impl DependencyInstallOpts { } } -pub fn install_missing_dependencies(config: &mut Config, quiet: bool) -> bool { - DependencyInstallOpts { quiet, ..Default::default() }.install_missing_dependencies(config) +pub fn install_missing_dependencies(config: &mut Config) -> bool { + DependencyInstallOpts::default().install_missing_dependencies(config) } #[derive(Clone, Copy, Debug)] @@ -415,9 +416,9 @@ impl Installer<'_> { // multiple candidates, ask the user to choose one or skip candidates.insert(0, String::from("SKIP AND USE ORIGINAL TAG")); - println!("There are multiple matching tags:"); + sh_println!("There are multiple matching tags:")?; for (i, candidate) in candidates.iter().enumerate() { - println!("[{i}] {candidate}"); + sh_println!("[{i}] {candidate}")?; } let n_candidates = candidates.len(); @@ -432,7 +433,7 @@ impl Installer<'_> { Ok(0) => return Ok(tag.into()), Ok(i) if (1..=n_candidates).contains(&i) => { let c = &candidates[i]; - println!("[{i}] {c} selected"); + sh_println!("[{i}] {c} selected")?; return Ok(c.clone()) } _ => continue, @@ -477,9 +478,9 @@ impl Installer<'_> { // multiple candidates, ask the user to choose one or skip candidates.insert(0, format!("{tag} (original branch)")); - println!("There are multiple matching branches:"); + sh_println!("There are multiple matching branches:")?; for (i, candidate) in candidates.iter().enumerate() { - println!("[{i}] {candidate}"); + sh_println!("[{i}] {candidate}")?; } let n_candidates = candidates.len(); @@ -491,7 +492,7 @@ impl Installer<'_> { // default selection, return None if input.is_empty() { - println!("Canceled branch matching"); + sh_println!("Canceled branch matching")?; return Ok(None) } @@ -500,7 +501,7 @@ impl Installer<'_> { Ok(0) => Ok(Some(tag.into())), Ok(i) if (1..=n_candidates).contains(&i) => { let c = &candidates[i]; - println!("[{i}] {c} selected"); + sh_println!("[{i}] {c} selected")?; Ok(Some(c.clone())) } _ => Ok(None), diff --git a/crates/forge/bin/cmd/mod.rs b/crates/forge/bin/cmd/mod.rs index ff63fa7cb..f2de1d632 100644 --- a/crates/forge/bin/cmd/mod.rs +++ b/crates/forge/bin/cmd/mod.rs @@ -44,6 +44,7 @@ pub mod bind_json; pub mod build; pub mod cache; pub mod clone; +pub mod compiler; pub mod config; pub mod coverage; pub mod create; diff --git a/crates/forge/bin/cmd/remappings.rs b/crates/forge/bin/cmd/remappings.rs index b33f3442c..dfa667ccc 100644 --- a/crates/forge/bin/cmd/remappings.rs +++ b/crates/forge/bin/cmd/remappings.rs @@ -30,20 +30,20 @@ impl RemappingArgs { } for (group, remappings) in groups { if let Some(group) = group { - println!("Context: {group}"); + sh_println!("Context: {group}")?; } else { - println!("Global:"); + sh_println!("Global:")?; } for mut remapping in remappings { remapping.context = None; // avoid writing context twice - println!("- {remapping}"); + sh_println!("- {remapping}")?; } - println!(); + sh_println!()?; } } else { for remapping in config.remappings { - println!("{remapping}"); + sh_println!("{remapping}")?; } } diff --git a/crates/forge/bin/cmd/remove.rs b/crates/forge/bin/cmd/remove.rs index a4d62b9f7..da2f8b251 100644 --- a/crates/forge/bin/cmd/remove.rs +++ b/crates/forge/bin/cmd/remove.rs @@ -38,7 +38,7 @@ impl RemoveArgs { // remove all the dependencies from .git/modules for (Dependency { name, url, tag, .. }, path) in self.dependencies.iter().zip(&paths) { - println!("Removing '{name}' in {}, (url: {url:?}, tag: {tag:?})", path.display()); + sh_println!("Removing '{name}' in {}, (url: {url:?}, tag: {tag:?})", path.display())?; std::fs::remove_dir_all(git_modules.join(path))?; } diff --git a/crates/forge/bin/cmd/selectors.rs b/crates/forge/bin/cmd/selectors.rs index 7b7bce2e5..ddd6a7968 100644 --- a/crates/forge/bin/cmd/selectors.rs +++ b/crates/forge/bin/cmd/selectors.rs @@ -120,13 +120,13 @@ impl SelectorsSubcommands { continue } - println!("Uploading selectors for {contract}..."); + sh_println!("Uploading selectors for {contract}...")?; // upload abi to selector database import_selectors(SelectorImportData::Abi(vec![abi])).await?.describe(); if artifacts.peek().is_some() { - println!() + sh_println!()? } } } @@ -171,7 +171,7 @@ impl SelectorsSubcommands { .collect(); if colliding_methods.is_empty() { - println!("No colliding method selectors between the two contracts."); + sh_println!("No colliding method selectors between the two contracts.")?; } else { let mut table = Table::new(); table.set_header([ @@ -182,12 +182,12 @@ impl SelectorsSubcommands { for method in colliding_methods.iter() { table.add_row([method.0, method.1, method.2]); } - println!("{} collisions found:", colliding_methods.len()); - println!("{table}"); + sh_println!("{} collisions found:", colliding_methods.len())?; + sh_println!("{table}")?; } } Self::List { contract, project_paths } => { - println!("Listing selectors for contracts in the project..."); + sh_println!("Listing selectors for contracts in the project...")?; let build_args = CoreBuildArgs { project_paths, compiler: CompilerArgs { @@ -240,7 +240,7 @@ impl SelectorsSubcommands { continue } - println!("{contract}"); + sh_println!("{contract}")?; let mut table = Table::new(); @@ -264,16 +264,16 @@ impl SelectorsSubcommands { table.add_row(["Error", &sig, &hex::encode_prefixed(selector)]); } - println!("{table}"); + sh_println!("{table}")?; if artifacts.peek().is_some() { - println!() + sh_println!()? } } } Self::Find { selector, project_paths } => { - println!("Searching for selector {selector:?} in the project..."); + sh_println!("Searching for selector {selector:?} in the project...")?; let build_args = CoreBuildArgs { project_paths, @@ -340,12 +340,10 @@ impl SelectorsSubcommands { } if table.row_count() > 0 { - println!(); - println!("Found {} instance(s)...", table.row_count()); - println!("{table}"); + sh_println!("\nFound {} instance(s)...", table.row_count())?; + sh_println!("{table}")?; } else { - println!(); - return Err(eyre::eyre!("Selector not found in the project.")); + return Err(eyre::eyre!("\nSelector not found in the project.")); } } } diff --git a/crates/forge/bin/cmd/snapshot.rs b/crates/forge/bin/cmd/snapshot.rs index 0d7c2843a..872a53138 100644 --- a/crates/forge/bin/cmd/snapshot.rs +++ b/crates/forge/bin/cmd/snapshot.rs @@ -96,7 +96,7 @@ impl GasSnapshotArgs { self.test.fuzz_seed = Some(U256::from_be_bytes(STATIC_FUZZ_SEED)); let outcome = self.test.execute_tests().await?; - outcome.ensure_ok()?; + outcome.ensure_ok(false)?; let tests = self.config.apply(outcome); if let Some(path) = self.diff { @@ -242,6 +242,7 @@ impl FromStr for GasSnapshotEntry { runs: runs.as_str().parse().unwrap(), calls: calls.as_str().parse().unwrap(), reverts: reverts.as_str().parse().unwrap(), + metrics: HashMap::default(), }, }) } @@ -330,7 +331,7 @@ fn check( { let source_gas = test.result.kind.report(); if !within_tolerance(source_gas.gas(), target_gas.gas(), tolerance) { - eprintln!( + let _ = sh_println!( "Diff in \"{}::{}\": consumed \"{}\" gas, expected \"{}\" gas ", test.contract_name(), test.signature, @@ -340,7 +341,7 @@ fn check( has_diff = true; } } else { - eprintln!( + let _ = sh_println!( "No matching snapshot entry found for \"{}::{}\" in snapshot file", test.contract_name(), test.signature @@ -381,20 +382,20 @@ fn diff(tests: Vec, snaps: Vec) -> Result<()> overall_gas_change += gas_change; overall_gas_used += diff.target_gas_used.gas() as i128; let gas_diff = diff.gas_diff(); - println!( + sh_println!( "{} (gas: {} ({})) ", diff.signature, fmt_change(gas_change), fmt_pct_change(gas_diff) - ); + )?; } let overall_gas_diff = overall_gas_change as f64 / overall_gas_used as f64; - println!( + sh_println!( "Overall gas change: {} ({})", fmt_change(overall_gas_change), fmt_pct_change(overall_gas_diff) - ); + )?; Ok(()) } @@ -486,7 +487,12 @@ mod tests { GasSnapshotEntry { contract_name: "Test".to_string(), signature: "deposit()".to_string(), - gas_used: TestKindReport::Invariant { runs: 256, calls: 100, reverts: 200 } + gas_used: TestKindReport::Invariant { + runs: 256, + calls: 100, + reverts: 200, + metrics: HashMap::default() + } } ); } @@ -500,7 +506,12 @@ mod tests { GasSnapshotEntry { contract_name: "ERC20Invariants".to_string(), signature: "invariantBalanceSum()".to_string(), - gas_used: TestKindReport::Invariant { runs: 256, calls: 3840, reverts: 2388 } + gas_used: TestKindReport::Invariant { + runs: 256, + calls: 3840, + reverts: 2388, + metrics: HashMap::default() + } } ); } diff --git a/crates/forge/bin/cmd/test/mod.rs b/crates/forge/bin/cmd/test/mod.rs index db66a5fdb..7d0a91ed9 100644 --- a/crates/forge/bin/cmd/test/mod.rs +++ b/crates/forge/bin/cmd/test/mod.rs @@ -20,7 +20,7 @@ use foundry_cli::{ opts::CoreBuildArgs, utils::{self, LoadConfig}, }; -use foundry_common::{cli_warn, compile::ProjectCompiler, evm::EvmArgs, fs, shell}; +use foundry_common::{compile::ProjectCompiler, evm::EvmArgs, fs, shell}; use foundry_compilers::{ artifacts::output_selection::OutputSelection, compilers::{multi::MultiCompilerLanguage, CompilerSettings, Language}, @@ -55,7 +55,9 @@ mod summary; use quick_junit::{NonSuccessKind, Report, TestCase, TestCaseStatus, TestSuite}; use summary::TestSummaryReporter; +use crate::cmd::test::summary::print_invariant_metrics; pub use filter::FilterArgs; +use forge::result::TestKind; // Loads project's figment and merges the build cli arguments into it foundry_config::merge_impl_figment_convert!(TestArgs, opts, evm_opts); @@ -100,6 +102,15 @@ pub struct TestArgs { #[arg(long, value_name = "DEPRECATED_TEST_FUNCTION_REGEX")] decode_internal: Option>, + /// Dumps all debugger steps to file. + #[arg( + long, + requires = "debug", + value_hint = ValueHint::FilePath, + value_name = "PATH" + )] + dump: Option, + /// Print a gas report. #[arg(long, env = "FORGE_GAS_REPORT")] gas_report: bool, @@ -108,13 +119,9 @@ pub struct TestArgs { #[arg(long, env = "FORGE_ALLOW_FAILURE")] allow_failure: bool, - /// Output test results in JSON format. - #[arg(long, help_heading = "Display options")] - json: bool, - /// Output test results as JUnit XML report. - #[arg(long, conflicts_with_all(["json", "gas_report"]), help_heading = "Display options")] - junit: bool, + #[arg(long, conflicts_with_all = ["quiet", "json", "gas_report"], help_heading = "Display options")] + pub junit: bool, /// Stop running tests after the first failure. #[arg(long)] @@ -182,7 +189,6 @@ impl TestArgs { pub async fn run(self) -> Result { trace!(target: "forge::test", "executing test command"); - shell::set_shell(shell::Shell::from_args(self.opts.silent, self.json || self.junit))?; self.execute_tests().await } @@ -202,7 +208,7 @@ impl TestArgs { let output = project.compile()?; if output.has_compiler_errors() { - println!("{output}"); + sh_println!("{output}")?; eyre::bail!("Compilation failed"); } @@ -221,13 +227,13 @@ impl TestArgs { if test_sources.is_empty() { if filter.is_empty() { - println!( + sh_println!( "No tests found in project! \ Forge looks for functions that starts with `test`." - ); + )?; } else { - println!("No tests match the provided pattern:"); - print!("{filter}"); + sh_println!("No tests match the provided pattern:")?; + sh_print!("{filter}")?; // Try to suggest a test when there's no match if let Some(test_pattern) = &filter.args().test_pattern { @@ -240,7 +246,7 @@ impl TestArgs { .flat_map(|(_, abi)| abi.functions.into_keys()) .collect::>(); if let Some(suggestion) = utils::did_you_mean(test_name, candidates).pop() { - println!("\nDid you mean `{suggestion}`?"); + sh_println!("\nDid you mean `{suggestion}`?")?; } } } @@ -287,9 +293,7 @@ impl TestArgs { let mut project = config.project()?; // Install missing dependencies. - if install::install_missing_dependencies(&mut config, self.build_args().silent) && - config.auto_detect_remappings - { + if install::install_missing_dependencies(&mut config) && config.auto_detect_remappings { // need to re-configure here to also catch additional remappings config = self.load_config(); project = config.project()?; @@ -300,9 +304,8 @@ impl TestArgs { let sources_to_compile = self.get_sources_to_compile(&config, &filter)?; - let compiler = ProjectCompiler::new() - .quiet_if(self.json || self.junit || self.opts.silent) - .files(sources_to_compile); + let compiler = + ProjectCompiler::new().quiet(shell::is_json() || self.junit).files(sources_to_compile); let output = compiler.compile(&project)?; @@ -311,9 +314,7 @@ impl TestArgs { foundry_zksync_compiler::config_create_project(&config, config.cache, false)?; let sources_to_compile = self.get_sources_to_compile(&config, &filter)?; - let zk_compiler = ProjectCompiler::new() - .quiet_if(self.json || self.opts.silent) - .files(sources_to_compile); + let zk_compiler = ProjectCompiler::new().files(sources_to_compile); let zk_output = zk_compiler.zksync_compile(&zk_project, config.zksync.avoid_contracts())?; @@ -396,10 +397,10 @@ impl TestArgs { let mut maybe_override_mt = |flag, maybe_regex: Option<&Option>| { if let Some(Some(regex)) = maybe_regex { - cli_warn!( + sh_warn!( "specifying argument for --{flag} is deprecated and will be removed in the future, \ use --match-test instead" - ); + )?; let test_pattern = &mut filter.args_mut().test_pattern; if test_pattern.is_some() { @@ -452,11 +453,11 @@ impl TestArgs { // Generate SVG. inferno::flamegraph::from_lines(&mut options, fst.iter().map(String::as_str), file) .wrap_err("failed to write svg")?; - println!("\nSaved to {file_name}"); + sh_println!("Saved to {file_name}")?; // Open SVG in default program. if let Err(e) = opener::open(&file_name) { - eprintln!("\nFailed to open {file_name}; please open it manually: {e}"); + sh_err!("Failed to open {file_name}; please open it manually: {e}")?; } } @@ -480,7 +481,11 @@ impl TestArgs { } let mut debugger = builder.build(); - debugger.try_run()?; + if let Some(dump_path) = self.dump { + debugger.dump_to_file(&dump_path)?; + } else { + debugger.try_run_tui()?; + } } Ok(outcome) @@ -496,13 +501,13 @@ impl TestArgs { output: &ProjectCompileOutput, ) -> eyre::Result { if self.list { - return list(runner, filter, self.json); + return list(runner, filter); } trace!(target: "forge::test", "running all tests"); // If we need to render to a serialized format, we should not print anything else to stdout. - let silent = self.gas_report && self.json; + let silent = self.gas_report && shell::is_json(); let num_filtered = runner.matching_test_functions(filter).count(); if num_filtered != 1 && (self.debug.is_some() || self.flamegraph || self.flamechart) { @@ -530,7 +535,7 @@ impl TestArgs { } // Run tests in a non-streaming fashion and collect results for serialization. - if !self.gas_report && self.json { + if !self.gas_report && shell::is_json() { let mut results = runner.test_collect(filter); results.values_mut().for_each(|suite_result| { for test_result in suite_result.test_results.values_mut() { @@ -543,13 +548,13 @@ impl TestArgs { } } }); - println!("{}", serde_json::to_string(&results)?); + sh_println!("{}", serde_json::to_string(&results)?)?; return Ok(TestOutcome::new(results, self.allow_failure)); } if self.junit { let results = runner.test_collect(filter); - println!("{}", junit_xml_report(&results, verbosity).to_string()?); + sh_println!("{}", junit_xml_report(&results, verbosity).to_string()?)?; return Ok(TestOutcome::new(results, self.allow_failure)); } @@ -599,7 +604,8 @@ impl TestArgs { GasReport::new( config.gas_reports.clone(), config.gas_reports_ignore.clone(), - if self.json { GasReportKind::JSON } else { GasReportKind::Markdown }, + config.gas_reports_include_tests, + if shell::is_json() { GasReportKind::JSON } else { GasReportKind::Markdown }, ) }); @@ -623,32 +629,39 @@ impl TestArgs { // Print suite header. if !silent { - println!(); + sh_println!()?; for warning in suite_result.warnings.iter() { - eprintln!("{} {warning}", "Warning:".yellow().bold()); + sh_warn!("{warning}")?; } if !tests.is_empty() { let len = tests.len(); let tests = if len > 1 { "tests" } else { "test" }; - println!("Ran {len} {tests} for {contract_name}"); + sh_println!("Ran {len} {tests} for {contract_name}")?; } } // Process individual test results, printing logs and traces when necessary. for (name, result) in tests { if !silent { - shell::println(result.short_result(name))?; + sh_println!("{}", result.short_result(name))?; + + // Display invariant metrics if invariant kind. + if let TestKind::Invariant { runs: _, calls: _, reverts: _, metrics } = + &result.kind + { + print_invariant_metrics(metrics); + } // We only display logs at level 2 and above if verbosity >= 2 { // We only decode logs from Hardhat and DS-style console events let console_logs = decode_console_logs(&result.logs); if !console_logs.is_empty() { - println!("Logs:"); + sh_println!("Logs:")?; for log in console_logs { - println!(" {log}"); + sh_println!(" {log}")?; } - println!(); + sh_println!()?; } } } @@ -692,9 +705,9 @@ impl TestArgs { } if !silent && !decoded_traces.is_empty() { - shell::println("Traces:")?; + sh_println!("Traces:")?; for trace in &decoded_traces { - shell::println(trace)?; + sh_println!("{trace}")?; } } @@ -759,13 +772,13 @@ impl TestArgs { .collect(); if !diff.is_empty() { - println!( + let _ = sh_eprintln!( "{}", format!("\n[{group}] Failed to match snapshots:").red().bold() ); for (key, (previous_snapshot, snapshot)) in &diff { - println!( + let _ = sh_eprintln!( "{}", format!("- [{key}] {previous_snapshot} → {snapshot}").red() ); @@ -779,7 +792,7 @@ impl TestArgs { ); if differences_found { - println!(); + sh_eprintln!()?; eyre::bail!("Snapshots differ from previous run"); } } @@ -799,7 +812,7 @@ impl TestArgs { // Print suite summary. if !silent { - shell::println(suite_result.summary())?; + sh_println!("{}", suite_result.summary())?; } // Add the suite result to the outcome. @@ -817,16 +830,16 @@ impl TestArgs { if let Some(gas_report) = gas_report { let finalized = gas_report.finalize(); - shell::println(&finalized)?; + sh_println!("{}", &finalized)?; outcome.gas_report = Some(finalized); } if !silent && !outcome.results.is_empty() { - shell::println(outcome.summary(duration))?; + sh_println!("{}", outcome.summary(duration))?; if self.summary { let mut summary_table = TestSummaryReporter::new(self.detailed); - shell::println("\n\nTest Summary:")?; + sh_println!("\n\nTest Summary:")?; summary_table.print_summary(&outcome); } } @@ -916,21 +929,17 @@ impl Provider for TestArgs { } /// Lists all matching tests -fn list( - runner: MultiContractRunner, - filter: &ProjectPathsAwareFilter, - json: bool, -) -> Result { +fn list(runner: MultiContractRunner, filter: &ProjectPathsAwareFilter) -> Result { let results = runner.list(filter); - if json { + if shell::is_json() { println!("{}", serde_json::to_string(&results)?); } else { for (file, contracts) in results.iter() { - println!("{file}"); + sh_println!("{file}")?; for (contract, tests) in contracts.iter() { - println!(" {contract}"); - println!(" {}\n", tests.join("\n ")); + sh_println!(" {contract}")?; + sh_println!(" {}\n", tests.join("\n "))?; } } } @@ -1007,34 +1016,56 @@ fn junit_xml_report(results: &BTreeMap, verbosity: u8) -> R #[cfg(test)] mod tests { + use crate::opts::{Forge, ForgeSubcommand}; + use super::*; use foundry_config::{Chain, InvariantConfig}; use foundry_test_utils::forgetest_async; #[test] fn watch_parse() { - let args: TestArgs = TestArgs::parse_from(["foundry-cli", "-vw"]); + let args = match Forge::parse_from(["foundry-cli", "test", "-vw"]).cmd { + ForgeSubcommand::Test(args) => args, + _ => unreachable!(), + }; assert!(args.watch.watch.is_some()); } #[test] fn fuzz_seed() { - let args: TestArgs = TestArgs::parse_from(["foundry-cli", "--fuzz-seed", "0x10"]); + let args = match Forge::parse_from(["foundry-cli", "test", "--fuzz-seed", "0x10"]).cmd { + ForgeSubcommand::Test(args) => args, + _ => unreachable!(), + }; assert!(args.fuzz_seed.is_some()); } // #[test] fn fuzz_seed_exists() { - let args: TestArgs = - TestArgs::parse_from(["foundry-cli", "-vvv", "--gas-report", "--fuzz-seed", "0x10"]); + let args = match Forge::parse_from([ + "foundry-cli", + "test", + "-vvv", + "--gas-report", + "--fuzz-seed", + "0x10", + ]) + .cmd + { + ForgeSubcommand::Test(args) => args, + _ => unreachable!(), + }; assert!(args.fuzz_seed.is_some()); } #[test] fn extract_chain() { let test = |arg: &str, expected: Chain| { - let args = TestArgs::parse_from(["foundry-cli", arg]); + let args = match Forge::parse_from(["foundry-cli", "test", arg]).cmd { + ForgeSubcommand::Test(args) => args, + _ => unreachable!(), + }; assert_eq!(args.evm_opts.env.chain, Some(expected)); let (config, evm_opts) = args.load_config_and_evm_opts().unwrap(); assert_eq!(config.chain, Some(expected)); @@ -1088,13 +1119,18 @@ contract FooBarTest is DSTest { ) .unwrap(); - let args = TestArgs::parse_from([ + let args = match Forge::parse_from([ "foundry-cli", + "test", "--gas-report", "--root", &prj.root().to_string_lossy(), - "--silent", - ]); + ]) + .cmd + { + ForgeSubcommand::Test(args) => args, + _ => unreachable!(), + }; let outcome = args.run().await.unwrap(); let gas_report = outcome.gas_report.unwrap(); diff --git a/crates/forge/bin/cmd/test/summary.rs b/crates/forge/bin/cmd/test/summary.rs index 561ea6b68..1922ce53b 100644 --- a/crates/forge/bin/cmd/test/summary.rs +++ b/crates/forge/bin/cmd/test/summary.rs @@ -1,7 +1,11 @@ use crate::cmd::test::TestOutcome; use comfy_table::{ - modifiers::UTF8_ROUND_CORNERS, Attribute, Cell, CellAlignment, Color, Row, Table, + modifiers::UTF8_ROUND_CORNERS, presets::ASCII_MARKDOWN, Attribute, Cell, CellAlignment, Color, + Row, Table, }; +use foundry_evm::executors::invariant::InvariantMetrics; +use itertools::Itertools; +use std::collections::HashMap; /// A simple summary reporter that prints the test results in a table. pub struct TestSummaryReporter { @@ -88,6 +92,40 @@ impl TestSummaryReporter { self.table.add_row(row); } - println!("\n{}", self.table); + let _ = sh_println!("\n{}", self.table); + } +} + +/// Helper to create and render invariant metrics summary table: +/// | Contract | Selector | Calls | Reverts | Discards | +/// |-----------------------|----------------|-------|---------|----------| +/// | AnotherCounterHandler | doWork | 7451 | 123 | 4941 | +/// | AnotherCounterHandler | doWorkThing | 7279 | 137 | 4849 | +/// | CounterHandler | doAnotherThing | 7302 | 150 | 4794 | +/// | CounterHandler | doSomething | 7382 | 160 | 4830 | +pub(crate) fn print_invariant_metrics(test_metrics: &HashMap) { + if !test_metrics.is_empty() { + let mut table = Table::new(); + table.load_preset(ASCII_MARKDOWN); + table.set_header(["Contract", "Selector", "Calls", "Reverts", "Discards"]); + + for name in test_metrics.keys().sorted() { + if let Some((contract, selector)) = + name.split_once(':').and_then(|(_, contract)| contract.split_once('.')) + { + let mut row = Row::new(); + row.add_cell(Cell::new(contract).set_alignment(CellAlignment::Left)); + row.add_cell(Cell::new(selector).set_alignment(CellAlignment::Left)); + if let Some(metrics) = test_metrics.get(name) { + row.add_cell(Cell::new(metrics.calls).set_alignment(CellAlignment::Center)); + row.add_cell(Cell::new(metrics.reverts).set_alignment(CellAlignment::Center)); + row.add_cell(Cell::new(metrics.discards).set_alignment(CellAlignment::Center)); + } + + table.add_row(row); + } + } + + let _ = sh_println!("{table}\n"); } } diff --git a/crates/forge/bin/cmd/watch.rs b/crates/forge/bin/cmd/watch.rs index 861002fd3..54d357c12 100644 --- a/crates/forge/bin/cmd/watch.rs +++ b/crates/forge/bin/cmd/watch.rs @@ -108,7 +108,9 @@ impl WatchArgs { ) -> Result { let config = watchexec::Config::default(); - config.on_error(|err| eprintln!("[[{err:?}]]")); + config.on_error(|err| { + let _ = sh_eprintln!("[[{err:?}]]"); + }); if let Some(delay) = &self.watch_delay { config.throttle(utils::parse_delay(delay)?); @@ -149,7 +151,7 @@ impl WatchArgs { let quit = |mut action: ActionHandler| { match quit_again.fetch_add(1, Ordering::Relaxed) { 0 => { - eprintln!( + let _ = sh_eprintln!( "[Waiting {stop_timeout:?} for processes to exit before stopping... \ Ctrl-C again to exit faster]" ); @@ -228,7 +230,7 @@ fn end_of_process(state: &CommandState) { let quiet = false; if !quiet { - eprintln!("{}", format!("[{msg}]").paint(fg.foreground())); + let _ = sh_eprintln!("{}", format!("[{msg}]").paint(fg.foreground())); } } diff --git a/crates/forge/bin/main.rs b/crates/forge/bin/main.rs index 1253d2682..9e4bb5499 100644 --- a/crates/forge/bin/main.rs +++ b/crates/forge/bin/main.rs @@ -1,10 +1,8 @@ -#[macro_use] -extern crate tracing; - use clap::{CommandFactory, Parser}; use clap_complete::generate; use eyre::Result; use foundry_cli::{handler, utils}; +use foundry_common::shell; use foundry_evm::inspectors::cheatcodes::{set_execution_context, ForgeContext}; mod cmd; @@ -13,36 +11,44 @@ use cmd::{cache::CacheSubcommands, generate::GenerateSubcommands, watch}; mod opts; use opts::{Forge, ForgeSubcommand}; +#[macro_use] +extern crate foundry_common; + +#[macro_use] +extern crate tracing; + #[cfg(all(feature = "jemalloc", unix))] #[global_allocator] static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; -fn main() -> Result<()> { +fn main() { + if let Err(err) = run() { + let _ = foundry_common::sh_err!("{err:?}"); + std::process::exit(1); + } +} + +fn run() -> Result<()> { handler::install(); utils::load_dotenv(); utils::subscriber(); utils::enable_paint(); - let opts = Forge::parse(); - init_execution_context(&opts.cmd); + let args = Forge::parse(); + args.shell.shell().set(); + init_execution_context(&args.cmd); - match opts.cmd { + match args.cmd { ForgeSubcommand::Test(cmd) => { if cmd.is_watch() { utils::block_on(watch::watch_test(cmd)) } else { + let silent = cmd.junit || shell::is_json(); let outcome = utils::block_on(cmd.run())?; - outcome.ensure_ok() + outcome.ensure_ok(silent) } } - ForgeSubcommand::Script(cmd) => { - // install the shell before executing the command - foundry_common::shell::set_shell(foundry_common::shell::Shell::from_args( - cmd.opts.silent, - cmd.json, - ))?; - utils::block_on(cmd.run_script()) - } + ForgeSubcommand::Script(cmd) => utils::block_on(cmd.run_script()), ForgeSubcommand::Coverage(cmd) => utils::block_on(cmd.run()), ForgeSubcommand::Bind(cmd) => cmd.run(), ForgeSubcommand::Build(cmd) => { @@ -121,6 +127,7 @@ fn main() -> Result<()> { ForgeSubcommand::Generate(cmd) => match cmd.sub { GenerateSubcommands::Test(cmd) => cmd.run(), }, + ForgeSubcommand::Compiler(cmd) => cmd.run(), ForgeSubcommand::Soldeer(cmd) => utils::block_on(cmd.run()), ForgeSubcommand::Eip712(cmd) => cmd.run(), ForgeSubcommand::BindJson(cmd) => cmd.run(), diff --git a/crates/forge/bin/opts.rs b/crates/forge/bin/opts.rs index c929d0185..39bc89e63 100644 --- a/crates/forge/bin/opts.rs +++ b/crates/forge/bin/opts.rs @@ -1,12 +1,14 @@ use crate::cmd::{ - bind::BindArgs, bind_json, build::BuildArgs, cache::CacheArgs, clone::CloneArgs, config, - coverage, create::CreateArgs, debug::DebugArgs, doc::DocArgs, eip712, flatten, fmt::FmtArgs, - geiger, generate, init::InitArgs, inspect, install::InstallArgs, remappings::RemappingArgs, - remove::RemoveArgs, selectors::SelectorsSubcommands, snapshot, soldeer, test, tree, update, + bind::BindArgs, bind_json, build::BuildArgs, cache::CacheArgs, clone::CloneArgs, + compiler::CompilerArgs, config, coverage, create::CreateArgs, debug::DebugArgs, doc::DocArgs, + eip712, flatten, fmt::FmtArgs, geiger, generate, init::InitArgs, inspect, install::InstallArgs, + remappings::RemappingArgs, remove::RemoveArgs, selectors::SelectorsSubcommands, snapshot, + soldeer, test, tree, update, }; use clap::{Parser, Subcommand, ValueHint}; use forge_script::ScriptArgs; use forge_verify::{VerifyArgs, VerifyBytecodeArgs, VerifyCheckArgs}; +use foundry_cli::opts::ShellOpts; use std::path::PathBuf; const VERSION_MESSAGE: &str = concat!( @@ -29,6 +31,9 @@ const VERSION_MESSAGE: &str = concat!( pub struct Forge { #[command(subcommand)] pub cmd: ForgeSubcommand, + + #[clap(flatten)] + pub shell: ShellOpts, } #[derive(Subcommand)] @@ -152,7 +157,7 @@ pub enum ForgeSubcommand { /// Generate documentation for the project. Doc(DocArgs), - /// Function selector utilities + /// Function selector utilities. #[command(visible_alias = "se")] Selectors { #[command(subcommand)] @@ -162,6 +167,9 @@ pub enum ForgeSubcommand { /// Generate scaffold files. Generate(generate::GenerateArgs), + /// Compiler utilities. + Compiler(CompilerArgs), + /// Soldeer dependency manager. Soldeer(soldeer::SoldeerArgs), diff --git a/crates/forge/src/coverage.rs b/crates/forge/src/coverage.rs index 4a00675dd..de8d0a8aa 100644 --- a/crates/forge/src/coverage.rs +++ b/crates/forge/src/coverage.rs @@ -55,7 +55,7 @@ impl CoverageReporter for SummaryReporter { } self.add_row("Total", self.total.clone()); - println!("{}", self.table); + sh_println!("{}", self.table)?; Ok(()) } } @@ -139,7 +139,7 @@ impl CoverageReporter for LcovReporter<'_> { writeln!(self.destination, "end_of_record")?; } - println!("Wrote LCOV report."); + sh_println!("Wrote LCOV report.")?; Ok(()) } @@ -151,30 +151,30 @@ pub struct DebugReporter; impl CoverageReporter for DebugReporter { fn report(self, report: &CoverageReport) -> eyre::Result<()> { for (path, items) in report.items_by_source() { - println!("Uncovered for {}:", path.display()); + sh_println!("Uncovered for {}:", path.display())?; items.iter().for_each(|item| { if item.hits == 0 { - println!("- {item}"); + let _ = sh_println!("- {item}"); } }); - println!(); + sh_println!()?; } for (contract_id, anchors) in &report.anchors { - println!("Anchors for {contract_id}:"); + sh_println!("Anchors for {contract_id}:")?; anchors .0 .iter() .map(|anchor| (false, anchor)) .chain(anchors.1.iter().map(|anchor| (true, anchor))) .for_each(|(is_deployed, anchor)| { - println!("- {anchor}"); + let _ = sh_println!("- {anchor}"); if is_deployed { - println!("- Creation code"); + let _ = sh_println!("- Creation code"); } else { - println!("- Runtime code"); + let _ = sh_println!("- Runtime code"); } - println!( + let _ = sh_println!( " - Refers to item: {}", report .items @@ -183,7 +183,7 @@ impl CoverageReporter for DebugReporter { .map_or("None".to_owned(), |item| item.to_string()) ); }); - println!(); + sh_println!()?; } Ok(()) diff --git a/crates/forge/src/gas_report.rs b/crates/forge/src/gas_report.rs index 6088f5678..1de748107 100644 --- a/crates/forge/src/gas_report.rs +++ b/crates/forge/src/gas_report.rs @@ -10,8 +10,8 @@ use foundry_common::{calc, TestFunctionExt}; use foundry_evm::traces::CallKind; use foundry_evm_abi::HARDHAT_CONSOLE_ADDRESS; use serde::{Deserialize, Serialize}; +use serde_json::json; use std::{collections::BTreeMap, fmt::Display}; -use yansi::Paint; #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] pub enum GasReportKind { @@ -36,6 +36,8 @@ pub struct GasReport { report_for: HashSet, /// Contracts to ignore when generating the report. ignore: HashSet, + /// Whether to include gas reports for tests. + include_tests: bool, /// All contracts that were analyzed grouped by their identifier /// ``test/Counter.t.sol:CounterTest pub contracts: BTreeMap, @@ -45,13 +47,14 @@ impl GasReport { pub fn new( report_for: impl IntoIterator, ignore: impl IntoIterator, + include_tests: bool, report_kind: GasReportKind, ) -> Self { let report_for = report_for.into_iter().collect::>(); let ignore = ignore.into_iter().collect::>(); let report_any = report_for.is_empty() || report_for.contains("*"); let report_type = report_kind; - Self { report_any, report_type, report_for, ignore, ..Default::default() } + Self { report_any, report_type, report_for, ignore, include_tests, ..Default::default() } } /// Whether the given contract should be reported. @@ -65,10 +68,8 @@ impl GasReport { // list. This is addressed this way because getting a report you don't expect is // preferable than not getting one you expect. A warning is printed to stderr // indicating the "double listing". - eprintln!( - "{}: {} is listed in both 'gas_reports' and 'gas_reports_ignore'.", - "warning".yellow().bold(), - contract_name + let _ = sh_warn!( + "{contract_name} is listed in both 'gas_reports' and 'gas_reports_ignore'." ); } return contains_anyway; @@ -128,7 +129,7 @@ impl GasReport { } else if let Some(DecodedCallData { signature, .. }) = decoded().await.call_data { let name = signature.split('(').next().unwrap(); // ignore any test/setup functions - if !name.test_function_kind().is_known() { + if self.include_tests || !name.test_function_kind().is_known() { trace!(contract_name, signature, "adding gas info"); let gas_info = contract_info .functions @@ -163,59 +164,109 @@ impl GasReport { impl Display for GasReport { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - for (name, contract) in &self.contracts { - if contract.functions.is_empty() { - trace!(name, "gas report contract without functions"); - continue; - } + match self.report_type { + GasReportKind::Markdown => { + for (name, contract) in &self.contracts { + if contract.functions.is_empty() { + trace!(name, "gas report contract without functions"); + continue; + } - if self.report_type == GasReportKind::JSON { - writeln!(f, "{}", serde_json::to_string(&contract).unwrap())?; - continue; + let table = self.format_table_output(contract, name); + writeln!(f, "{table}")?; + writeln!(f, "\n")?; + } + } + GasReportKind::JSON => { + writeln!(f, "{}", &self.format_json_output())?; } - - let mut table = Table::new(); - table.load_preset(ASCII_MARKDOWN); - table.set_header([Cell::new(format!("{name} contract")) - .add_attribute(Attribute::Bold) - .fg(Color::Green)]); - table.add_row([ - Cell::new("Deployment Cost").add_attribute(Attribute::Bold).fg(Color::Cyan), - Cell::new("Deployment Size").add_attribute(Attribute::Bold).fg(Color::Cyan), - ]); - table.add_row([contract.gas.to_string(), contract.size.to_string()]); - - table.add_row([ - Cell::new("Function Name").add_attribute(Attribute::Bold).fg(Color::Magenta), - Cell::new("min").add_attribute(Attribute::Bold).fg(Color::Green), - Cell::new("avg").add_attribute(Attribute::Bold).fg(Color::Yellow), - Cell::new("median").add_attribute(Attribute::Bold).fg(Color::Yellow), - Cell::new("max").add_attribute(Attribute::Bold).fg(Color::Red), - Cell::new("# calls").add_attribute(Attribute::Bold), - ]); - contract.functions.iter().for_each(|(fname, sigs)| { - sigs.iter().for_each(|(sig, gas_info)| { - // show function signature if overloaded else name - let fn_display = - if sigs.len() == 1 { fname.clone() } else { sig.replace(':', "") }; - - table.add_row([ - Cell::new(fn_display).add_attribute(Attribute::Bold), - Cell::new(gas_info.min.to_string()).fg(Color::Green), - Cell::new(gas_info.mean.to_string()).fg(Color::Yellow), - Cell::new(gas_info.median.to_string()).fg(Color::Yellow), - Cell::new(gas_info.max.to_string()).fg(Color::Red), - Cell::new(gas_info.calls.to_string()), - ]); - }) - }); - writeln!(f, "{table}")?; - writeln!(f, "\n")?; } + Ok(()) } } +impl GasReport { + fn format_json_output(&self) -> String { + serde_json::to_string( + &self + .contracts + .iter() + .filter_map(|(name, contract)| { + if contract.functions.is_empty() { + trace!(name, "gas report contract without functions"); + return None; + } + + let functions = contract + .functions + .iter() + .flat_map(|(_, sigs)| { + sigs.iter().map(|(sig, gas_info)| { + let display_name = sig.replace(':', ""); + (display_name, gas_info) + }) + }) + .collect::>(); + + Some(json!({ + "contract": name, + "deployment": { + "gas": contract.gas, + "size": contract.size, + }, + "functions": functions, + })) + }) + .collect::>(), + ) + .unwrap() + } + + // Helper function to format the table output + fn format_table_output(&self, contract: &ContractInfo, name: &str) -> Table { + let mut table = Table::new(); + table.load_preset(ASCII_MARKDOWN); + table.set_header([Cell::new(format!("{name} contract")) + .add_attribute(Attribute::Bold) + .fg(Color::Green)]); + + table.add_row([ + Cell::new("Deployment Cost").add_attribute(Attribute::Bold).fg(Color::Cyan), + Cell::new("Deployment Size").add_attribute(Attribute::Bold).fg(Color::Cyan), + ]); + table.add_row([contract.gas.to_string(), contract.size.to_string()]); + + table.add_row([ + Cell::new("Function Name").add_attribute(Attribute::Bold).fg(Color::Magenta), + Cell::new("min").add_attribute(Attribute::Bold).fg(Color::Green), + Cell::new("avg").add_attribute(Attribute::Bold).fg(Color::Yellow), + Cell::new("median").add_attribute(Attribute::Bold).fg(Color::Yellow), + Cell::new("max").add_attribute(Attribute::Bold).fg(Color::Red), + Cell::new("# calls").add_attribute(Attribute::Bold), + ]); + + contract.functions.iter().for_each(|(fname, sigs)| { + sigs.iter().for_each(|(sig, gas_info)| { + // Show function signature if overloaded else display function name. + let display_name = + if sigs.len() == 1 { fname.to_string() } else { sig.replace(':', "") }; + + table.add_row([ + Cell::new(display_name).add_attribute(Attribute::Bold), + Cell::new(gas_info.min.to_string()).fg(Color::Green), + Cell::new(gas_info.mean.to_string()).fg(Color::Yellow), + Cell::new(gas_info.median.to_string()).fg(Color::Yellow), + Cell::new(gas_info.max.to_string()).fg(Color::Red), + Cell::new(gas_info.calls.to_string()), + ]); + }) + }); + + table + } +} + #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct ContractInfo { pub gas: u64, diff --git a/crates/forge/src/lib.rs b/crates/forge/src/lib.rs index 6c6552d05..0bec55153 100644 --- a/crates/forge/src/lib.rs +++ b/crates/forge/src/lib.rs @@ -1,6 +1,9 @@ #![doc = include_str!("../README.md")] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#[macro_use] +extern crate foundry_common; + #[macro_use] extern crate tracing; diff --git a/crates/forge/src/progress.rs b/crates/forge/src/progress.rs index 2b45d5513..9ca182f76 100644 --- a/crates/forge/src/progress.rs +++ b/crates/forge/src/progress.rs @@ -48,7 +48,7 @@ impl TestsProgressState { pub fn end_suite_progress(&mut self, suite_name: &String, result_summary: String) { if let Some(suite_progress) = self.suites_progress.remove(suite_name) { self.multi.suspend(|| { - println!("{suite_name}\n ↪ {result_summary}"); + let _ = sh_println!("{suite_name}\n ↪ {result_summary}"); }); suite_progress.finish_and_clear(); // Increment test progress bar to reflect completed test suite. diff --git a/crates/forge/src/result.rs b/crates/forge/src/result.rs index 4fb88dfd0..60c07472e 100644 --- a/crates/forge/src/result.rs +++ b/crates/forge/src/result.rs @@ -13,13 +13,13 @@ use foundry_common::{evm::Breakpoints, get_contract_name, get_file_name, shell}; use foundry_evm::{ coverage::HitMaps, decode::SkipReason, - executors::{EvmError, RawCallResult}, + executors::{invariant::InvariantMetrics, EvmError, RawCallResult}, fuzz::{CounterExample, FuzzCase, FuzzFixtures, FuzzTestResult}, traces::{CallTraceArena, CallTraceDecoder, TraceKind, Traces}, }; use serde::{Deserialize, Serialize}; use std::{ - collections::BTreeMap, + collections::{BTreeMap, HashMap as Map}, fmt::{self, Write}, time::Duration, }; @@ -151,20 +151,19 @@ impl TestOutcome { } /// Checks if there are any failures and failures are disallowed. - pub fn ensure_ok(&self) -> eyre::Result<()> { + pub fn ensure_ok(&self, silent: bool) -> eyre::Result<()> { let outcome = self; let failures = outcome.failures().count(); if outcome.allow_failure || failures == 0 { return Ok(()); } - if !shell::verbosity().is_normal() { + if shell::is_quiet() || silent { // TODO: Avoid process::exit std::process::exit(1); } - shell::println("")?; - shell::println("Failing tests:")?; + sh_println!("\nFailing tests:")?; for (suite_name, suite) in outcome.results.iter() { let failed = suite.failed(); if failed == 0 { @@ -172,18 +171,18 @@ impl TestOutcome { } let term = if failed > 1 { "tests" } else { "test" }; - shell::println(format!("Encountered {failed} failing {term} in {suite_name}"))?; + sh_println!("Encountered {failed} failing {term} in {suite_name}")?; for (name, result) in suite.failures() { - shell::println(result.short_result(name))?; + sh_println!("{}", result.short_result(name))?; } - shell::println("")?; + sh_println!()?; } let successes = outcome.passed(); - shell::println(format!( + sh_println!( "Encountered a total of {} failing tests, {} tests succeeded", failures.to_string().red(), successes.to_string().green() - ))?; + )?; // TODO: Avoid process::exit std::process::exit(1); @@ -579,7 +578,8 @@ impl TestResult { /// Returns the skipped result for invariant test. pub fn invariant_skip(mut self, reason: SkipReason) -> Self { - self.kind = TestKind::Invariant { runs: 1, calls: 1, reverts: 1 }; + self.kind = + TestKind::Invariant { runs: 1, calls: 1, reverts: 1, metrics: HashMap::default() }; self.status = TestStatus::Skipped; self.reason = reason.0; self @@ -592,7 +592,8 @@ impl TestResult { invariant_name: &String, call_sequence: Vec, ) -> Self { - self.kind = TestKind::Invariant { runs: 1, calls: 1, reverts: 1 }; + self.kind = + TestKind::Invariant { runs: 1, calls: 1, reverts: 1, metrics: HashMap::default() }; self.status = TestStatus::Failure; self.reason = if replayed_entirely { Some(format!("{invariant_name} replay failure")) @@ -605,13 +606,15 @@ impl TestResult { /// Returns the fail result for invariant test setup. pub fn invariant_setup_fail(mut self, e: Report) -> Self { - self.kind = TestKind::Invariant { runs: 0, calls: 0, reverts: 0 }; + self.kind = + TestKind::Invariant { runs: 0, calls: 0, reverts: 0, metrics: HashMap::default() }; self.status = TestStatus::Failure; self.reason = Some(format!("failed to set up invariant testing environment: {e}")); self } /// Returns the invariant test result. + #[allow(clippy::too_many_arguments)] pub fn invariant_result( mut self, gas_report_traces: Vec>, @@ -620,11 +623,13 @@ impl TestResult { counterexample: Option, cases: Vec, reverts: usize, + metrics: Map, ) -> Self { self.kind = TestKind::Invariant { runs: cases.len(), calls: cases.iter().map(|sequence| sequence.cases().len()).sum(), reverts, + metrics, }; self.status = match success { true => TestStatus::Success, @@ -669,19 +674,19 @@ impl TestResult { pub enum TestKindReport { Unit { gas: u64 }, Fuzz { runs: usize, mean_gas: u64, median_gas: u64 }, - Invariant { runs: usize, calls: usize, reverts: usize }, + Invariant { runs: usize, calls: usize, reverts: usize, metrics: Map }, } impl fmt::Display for TestKindReport { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { + match self { Self::Unit { gas } => { write!(f, "(gas: {gas})") } Self::Fuzz { runs, mean_gas, median_gas } => { write!(f, "(runs: {runs}, μ: {mean_gas}, ~: {median_gas})") } - Self::Invariant { runs, calls, reverts } => { + Self::Invariant { runs, calls, reverts, metrics: _ } => { write!(f, "(runs: {runs}, calls: {calls}, reverts: {reverts})") } } @@ -715,7 +720,7 @@ pub enum TestKind { median_gas: u64, }, /// An invariant test. - Invariant { runs: usize, calls: usize, reverts: usize }, + Invariant { runs: usize, calls: usize, reverts: usize, metrics: Map }, } impl Default for TestKind { @@ -727,14 +732,17 @@ impl Default for TestKind { impl TestKind { /// The gas consumed by this test pub fn report(&self) -> TestKindReport { - match *self { - Self::Unit { gas } => TestKindReport::Unit { gas }, + match self { + Self::Unit { gas } => TestKindReport::Unit { gas: *gas }, Self::Fuzz { first_case: _, runs, mean_gas, median_gas } => { - TestKindReport::Fuzz { runs, mean_gas, median_gas } - } - Self::Invariant { runs, calls, reverts } => { - TestKindReport::Invariant { runs, calls, reverts } + TestKindReport::Fuzz { runs: *runs, mean_gas: *mean_gas, median_gas: *median_gas } } + Self::Invariant { runs, calls, reverts, metrics: _ } => TestKindReport::Invariant { + runs: *runs, + calls: *calls, + reverts: *reverts, + metrics: HashMap::default(), + }, } } } diff --git a/crates/forge/src/runner.rs b/crates/forge/src/runner.rs index 74e98d197..7d5330fe4 100644 --- a/crates/forge/src/runner.rs +++ b/crates/forge/src/runner.rs @@ -521,6 +521,11 @@ impl ContractRunner<'_> { invariant_contract.call_after_invariant, ) { if !success { + let _= sh_warn!("\ + Replayed invariant failure from {:?} file. \ + Run `forge clean` or remove file to ignore failure and to continue invariant test campaign.", + failure_file.as_path() + ); // If sequence still fails then replay error to collect traces and // exit without executing new runs. let _ = replay_run( @@ -625,6 +630,7 @@ impl ContractRunner<'_> { counterexample, invariant_result.cases, invariant_result.reverts, + invariant_result.metrics, ) } diff --git a/crates/forge/tests/cli/build.rs b/crates/forge/tests/cli/build.rs index af7d9cbf6..2cf60fb46 100644 --- a/crates/forge/tests/cli/build.rs +++ b/crates/forge/tests/cli/build.rs @@ -1,9 +1,38 @@ +use crate::utils::generate_large_contract; use foundry_config::Config; use foundry_test_utils::{forgetest, snapbox::IntoData, str, util::OutputExt}; use globset::Glob; use regex::Regex; -// tests that json is printed when --json is passed +forgetest_init!(can_parse_build_filters, |prj, cmd| { + prj.clear(); + + cmd.args(["build", "--names", "--skip", "tests", "scripts"]).assert_success().stdout_eq(str![ + [r#" +[COMPILING_FILES] with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! + compiler version: [..] + - Counter + +"#] + ]); +}); + +forgetest!(throws_on_conflicting_args, |prj, cmd| { + prj.clear(); + + cmd.args(["compile", "--format-json", "--quiet"]).assert_failure().stderr_eq(str![[r#" +error: the argument '--json' cannot be used with '--quiet' + +Usage: forge[..] build --json [PATHS]... + +For more information, try '--help'. + +"#]]); +}); + +// tests that json is printed when --format-json is passed forgetest!(compile_json, |prj, cmd| { prj.add_source( "jsonError", @@ -43,6 +72,32 @@ contract Dummy { "#]].is_json()); }); +forgetest!(initcode_size_exceeds_limit, |prj, cmd| { + prj.add_source("LargeContract", generate_large_contract(5450).as_str()).unwrap(); + cmd.args(["build", "--sizes"]).assert_failure().stdout_eq(str![ + r#" +... +| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) | +|--------------|------------------|-------------------|--------------------|---------------------| +| HugeContract | 202 | 49,359 | 24,374 | -207 | +... +"# + ]); +}); + +forgetest!(initcode_size_limit_can_be_ignored, |prj, cmd| { + prj.add_source("LargeContract", generate_large_contract(5450).as_str()).unwrap(); + cmd.args(["build", "--sizes", "--ignore-eip-3860"]).assert_success().stdout_eq(str![ + r#" +... +| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) | +|--------------|------------------|-------------------|--------------------|---------------------| +| HugeContract | 202 | 49,359 | 24,374 | -207 | +... +"# + ]); +}); + // tests build output is as expected forgetest_init!(exact_build_output, |prj, cmd| { cmd.args(["build", "--force"]).assert_success().stdout_eq(str![[r#" @@ -58,9 +113,9 @@ forgetest_init!(build_sizes_no_forge_std, |prj, cmd| { cmd.args(["build", "--sizes"]).assert_success().stdout_eq(str![ r#" ... -| Contract | Size (B) | Margin (B) | -|----------|----------|------------| -| Counter | 247 | 24,329 | +| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) | +|----------|------------------|-------------------|--------------------|---------------------| +| Counter | 247 | 277 | 24,329 | 48,875 | ... "# ]); @@ -70,7 +125,9 @@ forgetest_init!(build_sizes_no_forge_std, |prj, cmd| { forgetest_init!(test_zk_build_sizes, |prj, cmd| { cmd.args(["build", "--sizes", "--zksync", "--evm-version", "shanghai"]); let stdout = cmd.assert_success().get_output().stdout_lossy(); - let pattern = Regex::new(r"\|\s*Counter\s*\|\s*800\s*\|\s*450,199\s*\|").unwrap(); + let pattern = + Regex::new(r"\|\s*Counter\s*\|\s*800\s*\|\s*800\s*\|\s*450,199\s*\|\s*450,199\s*\|") + .unwrap(); assert!(pattern.is_match(&stdout), "Unexpected size output:\n{stdout}"); }); diff --git a/crates/forge/tests/cli/cmd.rs b/crates/forge/tests/cli/cmd.rs index fcead9cb0..e14014155 100644 --- a/crates/forge/tests/cli/cmd.rs +++ b/crates/forge/tests/cli/cmd.rs @@ -31,8 +31,29 @@ Commands: ... Options: - -h, --help Print help - -V, --version Print version + -h, --help + Print help (see a summary with '-h') + + -V, --version + Print version + +Display options: + --color + Log messages coloring + + Possible values: + - auto: Intelligently guess whether to use color output (default) + - always: Force color output + - never: Force disable color output + + --json + Format log messages as JSON + + -q, --quiet + Do not print log messages + + --verbose + Use verbose output Find more information in the book: http://book.getfoundry.sh/reference/forge/forge.html @@ -226,13 +247,20 @@ forgetest!(can_init_repo_with_config, |prj, cmd| { let foundry_toml = prj.root().join(Config::FILE_NAME); assert!(!foundry_toml.exists()); - cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" -Target directory is not empty, but `--force` was specified + cmd.args(["init", "--force"]) + .arg(prj.root()) + .assert_success() + .stdout_eq(str![[r#" Initializing [..]... Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) Installed forge-std[..] Initialized forge project +"#]]) + .stderr_eq(str![[r#" +Warning: Target directory is not empty, but `--force` was specified +... + "#]]); let s = read_string(&foundry_toml); @@ -254,8 +282,7 @@ forgetest!(can_detect_dirty_git_status_on_init, |prj, cmd| { cmd.current_dir(&nested); cmd.arg("init").assert_failure().stderr_eq(str![[r#" -Error: -The target directory is a part of or on its own an already initialized git repository, +Error: The target directory is a part of or on its own an already initialized git repository, and it requires clean working and staging areas, including no untracked files. Check the current git repository's status with `git status`. @@ -350,19 +377,24 @@ Initializing [..] from https://github.com/foundry-rs/forge-template... forgetest!(can_init_non_empty, |prj, cmd| { prj.create_file("README.md", "non-empty dir"); cmd.arg("init").arg(prj.root()).assert_failure().stderr_eq(str![[r#" -Error: -Cannot run `init` on a non-empty directory. +Error: Cannot run `init` on a non-empty directory. Run with the `--force` flag to initialize regardless. "#]]); - cmd.arg("--force").assert_success().stdout_eq(str![[r#" -Target directory is not empty, but `--force` was specified + cmd.arg("--force") + .assert_success() + .stdout_eq(str![[r#" Initializing [..]... Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) Installed forge-std[..] Initialized forge project +"#]]) + .stderr_eq(str![[r#" +Warning: Target directory is not empty, but `--force` was specified +... + "#]]); assert!(prj.root().join(".git").exists()); @@ -385,20 +417,26 @@ forgetest!(can_init_in_empty_repo, |prj, cmd| { assert!(root.join(".git").exists()); cmd.arg("init").arg(root).assert_failure().stderr_eq(str![[r#" -Error: -Cannot run `init` on a non-empty directory. +Error: Cannot run `init` on a non-empty directory. Run with the `--force` flag to initialize regardless. "#]]); - cmd.arg("--force").assert_success().stdout_eq(str![[r#" -Target directory is not empty, but `--force` was specified + cmd.arg("--force") + .assert_success() + .stdout_eq(str![[r#" Initializing [..]... Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) Installed forge-std[..] Initialized forge project +"#]]) + .stderr_eq(str![[r#" +Warning: Target directory is not empty, but `--force` was specified +... + "#]]); + assert!(root.join("lib/forge-std").exists()); }); @@ -421,20 +459,26 @@ forgetest!(can_init_in_non_empty_repo, |prj, cmd| { prj.create_file(".gitignore", "not foundry .gitignore"); cmd.arg("init").arg(root).assert_failure().stderr_eq(str![[r#" -Error: -Cannot run `init` on a non-empty directory. +Error: Cannot run `init` on a non-empty directory. Run with the `--force` flag to initialize regardless. "#]]); - cmd.arg("--force").assert_success().stdout_eq(str![[r#" -Target directory is not empty, but `--force` was specified + cmd.arg("--force") + .assert_success() + .stdout_eq(str![[r#" Initializing [..]... Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) Installed forge-std[..] Initialized forge project +"#]]) + .stderr_eq(str![[r#" +Warning: Target directory is not empty, but `--force` was specified +... + "#]]); + assert!(root.join("lib/forge-std").exists()); // not overwritten @@ -521,8 +565,7 @@ forgetest!(fail_init_nonexistent_template, |prj, cmd| { cmd.args(["init", "--template", "a"]).arg(prj.root()).assert_failure().stderr_eq(str![[r#" remote: Not Found fatal: repository 'https://github.com/a/' not found -Error: -git fetch exited with code 128 +Error: git fetch exited with code 128 "#]]); }); @@ -1073,8 +1116,7 @@ Warning: SPDX license identifier not provided in source file. Before publishing, prj.write_config(config); cmd.forge_fuse().args(["build", "--force"]).assert_failure().stderr_eq(str![[r#" -Error: -Compiler run failed: +Error: Compiler run failed: Warning (1878): SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. [FILE] @@ -1152,8 +1194,7 @@ contract CTest is DSTest { // `forge build --force` which should fail cmd.forge_fuse().args(["build", "--force"]).assert_failure().stderr_eq(str![[r#" -Error: -Compiler run failed: +Error: Compiler run failed: Error (2314): Expected ';' but got identifier [FILE]:7:19: | @@ -1169,8 +1210,7 @@ Error (2314): Expected ';' but got identifier // still errors cmd.forge_fuse().args(["build", "--force"]).assert_failure().stderr_eq(str![[r#" -Error: -Compiler run failed: +Error: Compiler run failed: Error (2314): Expected ';' but got identifier [FILE]:7:19: | @@ -1210,8 +1250,7 @@ Compiler run successful! // introduce the error again but building without force prj.add_source("CTest.t.sol", syntax_err).unwrap(); cmd.forge_fuse().arg("build").assert_failure().stderr_eq(str![[r#" -Error: -Compiler run failed: +Error: Compiler run failed: Error (2314): Expected ';' but got identifier [FILE]:7:19: | @@ -1556,16 +1595,61 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo()": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz()": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar()": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); prj.write_config(Config { gas_reports: (vec![]), ..Default::default() }); cmd.forge_fuse().arg("test").arg("--gas-report").assert_success().stdout_eq(str![[r#" @@ -1595,16 +1679,61 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo()": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz()": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar()": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); prj.write_config(Config { gas_reports: (vec!["*".to_string()]), ..Default::default() }); cmd.forge_fuse().arg("test").arg("--gas-report").assert_success().stdout_eq(str![[r#" @@ -1634,16 +1763,61 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo()": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz()": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar()": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); prj.write_config(Config { gas_reports: (vec![ @@ -1680,16 +1854,61 @@ forgetest!(gas_report_all_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo()": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz()": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar()": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); }); forgetest!(gas_report_some_contracts, |prj, cmd| { @@ -1710,14 +1929,29 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo()": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + } +] +"#]] + .is_json(), + ); // report for Two prj.write_config(Config { gas_reports: vec!["ContractTwo".to_string()], ..Default::default() }); @@ -1735,8 +1969,26 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { "#]]); cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( str![[r#" -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines(), +[ + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar()": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), ); // report for Three @@ -1756,17 +2008,32 @@ forgetest!(gas_report_some_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz()": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + } +] +"#]] + .is_json(), + ); }); -forgetest!(gas_ignore_some_contracts, |prj, cmd| { +forgetest!(gas_report_ignore_some_contracts, |prj, cmd| { prj.insert_ds_test(); prj.add_source("Contracts.sol", GAS_REPORT_CONTRACTS).unwrap(); @@ -1796,15 +2063,45 @@ forgetest!(gas_ignore_some_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz()": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar()": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ); // ignore ContractTwo cmd.forge_fuse(); @@ -1833,17 +2130,51 @@ forgetest!(gas_ignore_some_contracts, |prj, cmd| { ... "#]]); - cmd.forge_fuse() - .arg("test") - .arg("--gas-report") - .arg("--json") - .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -"#]].is_jsonlines()); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo()": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz()": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + } +] +"#]] + .is_json(), + ); - // ignore ContractThree + // If the user listed the contract in 'gas_reports' (the foundry.toml field) a + // report for the contract is generated even if it's listed in the ignore + // list. This is addressed this way because getting a report you don't expect is + // preferable than not getting one you expect. A warning is printed to stderr + // indicating the "double listing". cmd.forge_fuse(); prj.write_config(Config { gas_reports: (vec![ @@ -1855,7 +2186,10 @@ forgetest!(gas_ignore_some_contracts, |prj, cmd| { ..Default::default() }); cmd.forge_fuse(); - cmd.arg("test").arg("--gas-report").assert_success().stdout_eq(str![[r#" + cmd.arg("test") + .arg("--gas-report") + .assert_success() + .stdout_eq(str![[r#" ... | src/Contracts.sol:ContractOne contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| @@ -1880,18 +2214,181 @@ forgetest!(gas_ignore_some_contracts, |prj, cmd| { | Function Name | min | avg | median | max | # calls | | bar | 64984 | 64984 | 64984 | 64984 | 1 | ... - +"#]]) + .stderr_eq(str![[r#" +... +Warning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'. +... "#]]); cmd.forge_fuse() .arg("test") .arg("--gas-report") .arg("--json") .assert_success() - .stdout_eq(str![[r#" -{"gas":103375,"size":255,"functions":{"foo":{"foo()":{"calls":1,"min":45387,"mean":45387,"median":45387,"max":45387}}}} -{"gas":103591,"size":256,"functions":{"baz":{"baz()":{"calls":1,"min":260712,"mean":260712,"median":260712,"max":260712}}}} -{"gas":103375,"size":255,"functions":{"bar":{"bar()":{"calls":1,"min":64984,"mean":64984,"median":64984,"max":64984}}}} -"#]].is_jsonlines()); + .stdout_eq( + str![[r#" +[ + { + "contract": "src/Contracts.sol:ContractOne", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "foo()": { + "calls": 1, + "min": 45387, + "mean": 45387, + "median": 45387, + "max": 45387 + } + } + }, + { + "contract": "src/Contracts.sol:ContractThree", + "deployment": { + "gas": 103591, + "size": 256 + }, + "functions": { + "baz()": { + "calls": 1, + "min": 260712, + "mean": 260712, + "median": 260712, + "max": 260712 + } + } + }, + { + "contract": "src/Contracts.sol:ContractTwo", + "deployment": { + "gas": 103375, + "size": 255 + }, + "functions": { + "bar()": { + "calls": 1, + "min": 64984, + "mean": 64984, + "median": 64984, + "max": 64984 + } + } + } +] +"#]] + .is_json(), + ) + .stderr_eq(str![[r#" +... +Warning: ContractThree is listed in both 'gas_reports' and 'gas_reports_ignore'. +... +"#]]); +}); + +forgetest!(gas_report_flatten_multiple_selectors, |prj, cmd| { + prj.insert_ds_test(); + prj.add_source( + "Counter.sol", + r#" +contract Counter { + uint256 public a; + int256 public b; + + function setNumber(uint256 x) public { + a = x; + } + + function setNumber(int256 x) public { + b = x; + } +} +"#, + ) + .unwrap(); + + prj.add_source( + "CounterTest.t.sol", + r#" +import "./test.sol"; +import {Counter} from "./Counter.sol"; + +contract CounterTest is DSTest { + Counter public counter; + + function setUp() public { + counter = new Counter(); + counter.setNumber(uint256(0)); + counter.setNumber(int256(0)); + } + + function test_Increment() public { + counter.setNumber(uint256(counter.a() + 1)); + counter.setNumber(int256(counter.b() + 1)); + } +} +"#, + ) + .unwrap(); + + cmd.arg("test").arg("--gas-report").assert_success().stdout_eq(str![[r#" +... +| src/Counter.sol:Counter contract | | | | | | +|----------------------------------|-----------------|-------|--------|-------|---------| +| Deployment Cost | Deployment Size | | | | | +| 101137 | 250 | | | | | +| Function Name | min | avg | median | max | # calls | +| a | 2261 | 2261 | 2261 | 2261 | 1 | +| b | 2305 | 2305 | 2305 | 2305 | 1 | +| setNumber(int256) | 23648 | 33604 | 33604 | 43560 | 2 | +| setNumber(uint256) | 23604 | 33560 | 33560 | 43516 | 2 | +... +"#]]); + cmd.forge_fuse().arg("test").arg("--gas-report").arg("--json").assert_success().stdout_eq( + str![[r#" +[ + { + "contract": "src/Counter.sol:Counter", + "deployment": { + "gas": 101137, + "size": 250 + }, + "functions": { + "a()": { + "calls": 1, + "min": 2261, + "mean": 2261, + "median": 2261, + "max": 2261 + }, + "b()": { + "calls": 1, + "min": 2305, + "mean": 2305, + "median": 2305, + "max": 2305 + }, + "setNumber(int256)": { + "calls": 2, + "min": 23648, + "mean": 33604, + "median": 33604, + "max": 43560 + }, + "setNumber(uint256)": { + "calls": 2, + "min": 23604, + "mean": 33560, + "median": 33560, + "max": 43516 + } + } + } +] +"#]] + .is_json(), + ); }); forgetest!(zk_gas_report, |prj, cmd| { @@ -2259,9 +2756,9 @@ forgetest_init!(can_build_sizes_repeatedly, |prj, cmd| { [COMPILING_FILES] with [SOLC_VERSION] [SOLC_VERSION] [ELAPSED] Compiler run successful! -| Contract | Size (B) | Margin (B) | -|----------|----------|------------| -| Counter | 247 | 24,329 | +| Contract | Runtime Size (B) | Initcode Size (B) | Runtime Margin (B) | Initcode Margin (B) | +|----------|------------------|-------------------|--------------------|---------------------| +| Counter | 247 | 277 | 24,329 | 48,875 | "#]]); @@ -2296,3 +2793,101 @@ interface Counter { "#]], ); }); + +// checks that `clean` also works with the "out" value set in Config +forgetest_init!(gas_report_include_tests, |prj, cmd| { + prj.write_config(Config { + gas_reports_include_tests: true, + fuzz: FuzzConfig { runs: 1, ..Default::default() }, + ..Default::default() + }); + + cmd.args(["test", "--mt", "test_Increment", "--gas-report"]).assert_success().stdout_eq(str![ + [r#" +... +| src/Counter.sol:Counter contract | | | | | | +|----------------------------------|-----------------|-------|--------|-------|---------| +| Deployment Cost | Deployment Size | | | | | +| 106715 | 277 | | | | | +| Function Name | min | avg | median | max | # calls | +| increment | 43404 | 43404 | 43404 | 43404 | 1 | +| number | 283 | 283 | 283 | 283 | 1 | +| setNumber | 23582 | 23582 | 23582 | 23582 | 1 | + + +| test/Counter.t.sol:CounterTest contract | | | | | | +|-----------------------------------------|-----------------|--------|--------|--------|---------| +| Deployment Cost | Deployment Size | | | | | +| 965418 | 4661 | | | | | +| Function Name | min | avg | median | max | # calls | +| setUp | 168064 | 168064 | 168064 | 168064 | 1 | +| test_Increment | 52367 | 52367 | 52367 | 52367 | 1 | +... + +"#] + ]); + + cmd.forge_fuse() + .args(["test", "--mt", "test_Increment", "--gas-report", "--json"]) + .assert_success() + .stdout_eq( + str![[r#" +[ + { + "contract": "src/Counter.sol:Counter", + "deployment": { + "gas": 106715, + "size": 277 + }, + "functions": { + "increment()": { + "calls": 1, + "min": 43404, + "mean": 43404, + "median": 43404, + "max": 43404 + }, + "number()": { + "calls": 1, + "min": 283, + "mean": 283, + "median": 283, + "max": 283 + }, + "setNumber(uint256)": { + "calls": 1, + "min": 23582, + "mean": 23582, + "median": 23582, + "max": 23582 + } + } + }, + { + "contract": "test/Counter.t.sol:CounterTest", + "deployment": { + "gas": 965418, + "size": 4661 + }, + "functions": { + "setUp()": { + "calls": 1, + "min": 168064, + "mean": 168064, + "median": 168064, + "max": 168064 + }, + "test_Increment()": { + "calls": 1, + "min": 52367, + "mean": 52367, + "median": 52367, + "max": 52367 + } + } + } +] +"#]] + .is_json(), + ); +}); diff --git a/crates/forge/tests/cli/compiler.rs b/crates/forge/tests/cli/compiler.rs new file mode 100644 index 000000000..b8453b67b --- /dev/null +++ b/crates/forge/tests/cli/compiler.rs @@ -0,0 +1,302 @@ +//! Tests for the `forge compiler` command. + +use foundry_test_utils::snapbox::IntoData; + +const CONTRACT_A: &str = r#" +// SPDX-license-identifier: MIT +pragma solidity 0.8.4; + +contract ContractA {} +"#; + +const CONTRACT_B: &str = r#" +// SPDX-license-identifier: MIT +pragma solidity 0.8.11; + +contract ContractB {} +"#; + +const CONTRACT_C: &str = r#" +// SPDX-license-identifier: MIT +pragma solidity 0.8.27; + +contract ContractC {} +"#; + +const CONTRACT_D: &str = r#" +// SPDX-license-identifier: MIT +pragma solidity 0.8.27; + +contract ContractD {} +"#; + +const VYPER_INTERFACE: &str = r#" +# pragma version >=0.4.0 + +@external +@view +def number() -> uint256: + return empty(uint256) + +@external +def set_number(new_number: uint256): + pass + +@external +def increment() -> uint256: + return empty(uint256) +"#; + +const VYPER_CONTRACT: &str = r#" +import ICounter +implements: ICounter + +number: public(uint256) + +@external +def set_number(new_number: uint256): + self.number = new_number + +@external +def increment() -> uint256: + self.number += 1 + return self.number +"#; + +forgetest!(can_resolve_path, |prj, cmd| { + prj.add_source("ContractA", CONTRACT_A).unwrap(); + + cmd.args(["compiler", "resolve", "--root", prj.root().to_str().unwrap()]) + .assert_success() + .stdout_eq(str![[r#" +Solidity: +- 0.8.4 + + +"#]]); +}); + +forgetest!(can_list_resolved_compiler_versions, |prj, cmd| { + prj.add_source("ContractA", CONTRACT_A).unwrap(); + + cmd.args(["compiler", "resolve"]).assert_success().stdout_eq(str![[r#" +Solidity: +- 0.8.4 + + +"#]]); +}); + +forgetest!(can_list_resolved_compiler_versions_json, |prj, cmd| { + prj.add_source("ContractA", CONTRACT_A).unwrap(); + + cmd.args(["compiler", "resolve", "--json"]).assert_success().stdout_eq( + str![[r#" +{ + "Solidity":[ + { + "version":"0.8.4" + } + ] +} +"#]] + .is_json(), + ); +}); + +forgetest!(can_list_resolved_compiler_versions_verbose, |prj, cmd| { + prj.add_source("ContractC", CONTRACT_C).unwrap(); + prj.add_source("ContractD", CONTRACT_D).unwrap(); + + cmd.args(["compiler", "resolve", "-v"]).assert_success().stdout_eq(str![[r#" +Solidity: + +0.8.27: +├── src/ContractC.sol +└── src/ContractD.sol + + +"#]]); +}); + +forgetest!(can_list_resolved_compiler_versions_verbose_json, |prj, cmd| { + prj.add_source("ContractC", CONTRACT_C).unwrap(); + prj.add_source("ContractD", CONTRACT_D).unwrap(); + + cmd.args(["compiler", "resolve", "--json", "-v"]).assert_success().stdout_eq( + str![[r#" +{ + "Solidity": [ + { + "version": "0.8.27", + "paths": [ + "src/ContractC.sol", + "src/ContractD.sol" + ] + } + ] +} +"#]] + .is_json(), + ); +}); + +forgetest!(can_list_resolved_multiple_compiler_versions, |prj, cmd| { + prj.add_source("ContractA", CONTRACT_A).unwrap(); + prj.add_source("ContractB", CONTRACT_B).unwrap(); + prj.add_source("ContractC", CONTRACT_C).unwrap(); + prj.add_source("ContractD", CONTRACT_D).unwrap(); + prj.add_raw_source("ICounter.vyi", VYPER_INTERFACE).unwrap(); + prj.add_raw_source("Counter.vy", VYPER_CONTRACT).unwrap(); + + cmd.args(["compiler", "resolve"]).assert_success().stdout_eq(str![[r#" +Solidity: +- 0.8.4 +- 0.8.11 +- 0.8.27 + +Vyper: +- 0.4.0 + + +"#]]); +}); + +forgetest!(can_list_resolved_multiple_compiler_versions_skipped, |prj, cmd| { + prj.add_source("ContractA", CONTRACT_A).unwrap(); + prj.add_source("ContractB", CONTRACT_B).unwrap(); + prj.add_source("ContractC", CONTRACT_C).unwrap(); + prj.add_source("ContractD", CONTRACT_D).unwrap(); + prj.add_raw_source("ICounter.vyi", VYPER_INTERFACE).unwrap(); + prj.add_raw_source("Counter.vy", VYPER_CONTRACT).unwrap(); + + cmd.args(["compiler", "resolve", "--skip", ".sol", "-v"]).assert_success().stdout_eq(str![[ + r#" +Vyper: + +0.4.0: +├── src/Counter.vy +└── src/ICounter.vyi + + +"# + ]]); +}); + +forgetest!(can_list_resolved_multiple_compiler_versions_skipped_json, |prj, cmd| { + prj.add_source("ContractA", CONTRACT_A).unwrap(); + prj.add_source("ContractB", CONTRACT_B).unwrap(); + prj.add_source("ContractC", CONTRACT_C).unwrap(); + prj.add_source("ContractD", CONTRACT_D).unwrap(); + prj.add_raw_source("ICounter.vyi", VYPER_INTERFACE).unwrap(); + prj.add_raw_source("Counter.vy", VYPER_CONTRACT).unwrap(); + + cmd.args(["compiler", "resolve", "--skip", "Contract(A|B|C)", "--json", "-v"]) + .assert_success() + .stdout_eq( + str![[r#" +{ + "Solidity": [ + { + "version": "0.8.27", + "paths": [ + "src/ContractD.sol" + ] + } + ], + "Vyper": [ + { + "version": "0.4.0", + "paths": [ + "src/Counter.vy", + "src/ICounter.vyi" + ] + } + ] +} +"#]] + .is_json(), + ); +}); + +forgetest!(can_list_resolved_multiple_compiler_versions_verbose, |prj, cmd| { + prj.add_source("ContractA", CONTRACT_A).unwrap(); + prj.add_source("ContractB", CONTRACT_B).unwrap(); + prj.add_source("ContractC", CONTRACT_C).unwrap(); + prj.add_source("ContractD", CONTRACT_D).unwrap(); + prj.add_raw_source("ICounter.vyi", VYPER_INTERFACE).unwrap(); + prj.add_raw_source("Counter.vy", VYPER_CONTRACT).unwrap(); + + cmd.args(["compiler", "resolve", "-vv"]).assert_success().stdout_eq(str![[r#" +Solidity: + +0.8.4 (<= istanbul): +└── src/ContractA.sol + +0.8.11 (<= london): +└── src/ContractB.sol + +0.8.27 (<= [..]): +├── src/ContractC.sol +└── src/ContractD.sol + +Vyper: + +0.4.0 (<= [..]): +├── src/Counter.vy +└── src/ICounter.vyi + + +"#]]); +}); + +forgetest!(can_list_resolved_multiple_compiler_versions_verbose_json, |prj, cmd| { + prj.add_source("ContractA", CONTRACT_A).unwrap(); + prj.add_source("ContractB", CONTRACT_B).unwrap(); + prj.add_source("ContractC", CONTRACT_C).unwrap(); + prj.add_source("ContractD", CONTRACT_D).unwrap(); + prj.add_raw_source("ICounter.vyi", VYPER_INTERFACE).unwrap(); + prj.add_raw_source("Counter.vy", VYPER_CONTRACT).unwrap(); + + cmd.args(["compiler", "resolve", "--json", "-vv"]).assert_success().stdout_eq( + str![[r#" +{ + "Solidity": [ + { + "version": "0.8.4", + "evm_version": "Istanbul", + "paths": [ + "src/ContractA.sol" + ] + }, + { + "version": "0.8.11", + "evm_version": "London", + "paths": [ + "src/ContractB.sol" + ] + }, + { + "version": "0.8.27", + "evm_version": "[..]", + "paths": [ + "src/ContractC.sol", + "src/ContractD.sol" + ] + } + ], + "Vyper": [ + { + "version": "0.4.0", + "evm_version": "[..]", + "paths": [ + "src/Counter.vy", + "src/ICounter.vyi" + ] + } + ] +} +"#]] + .is_json(), + ); +}); diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index e84137dbc..28b43dbfd 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -43,6 +43,7 @@ forgetest!(can_extract_config_values, |prj, cmd| { evm_version: EvmVersion::Byzantium, gas_reports: vec!["Contract".to_string()], gas_reports_ignore: vec![], + gas_reports_include_tests: false, solc: Some(SolcReq::Local(PathBuf::from("custom-solc"))), auto_detect_solc: false, auto_detect_remappings: true, @@ -105,6 +106,7 @@ forgetest!(can_extract_config_values, |prj, cmd| { memory_limit: 1 << 27, eth_rpc_url: Some("localhost".to_string()), eth_rpc_jwt: None, + eth_rpc_timeout: None, etherscan_api_key: None, etherscan: Default::default(), verbosity: 4, @@ -261,7 +263,7 @@ forgetest_init!(can_parse_remappings_correctly, |prj, cmd| { cmd.forge_fuse().args(["install", dep, "--no-commit"]).assert_success().stdout_eq(str![[ r#" Installing solmate in [..] (url: Some("https://github.com/transmissions11/solmate"), tag: None) - Installed solmate + Installed solmate[..] "# ]]); @@ -398,8 +400,7 @@ Compiler run successful! // fails to use solc that does not exist cmd.forge_fuse().args(["build", "--use", "this/solc/does/not/exist"]); cmd.assert_failure().stderr_eq(str![[r#" -Error: -`solc` this/solc/does/not/exist does not exist +Error: `solc` this/solc/does/not/exist does not exist "#]]); @@ -435,8 +436,7 @@ contract Foo { .unwrap(); cmd.arg("build").assert_failure().stderr_eq(str![[r#" -Error: -Compiler run failed: +Error: Compiler run failed: Error (6553): The msize instruction cannot be used when the Yul optimizer is activated because it can change its semantics. Either disable the Yul optimizer or do not use the instruction. [FILE]:6:8: | @@ -596,6 +596,44 @@ forgetest_init!(can_prioritise_closer_lib_remappings, |prj, cmd| { ); }); +// Test that remappings within root of the project have priority over remappings of sub-projects. +// E.g. `@utils/libraries` mapping from library shouldn't be added if project already has `@utils` +// remapping. +// See +forgetest_init!(test_root_remappings_priority, |prj, cmd| { + let mut config = cmd.config(); + // Add `@utils/` remapping in project config. + config.remappings = vec![ + Remapping::from_str("@utils/=src/").unwrap().into(), + Remapping::from_str("@another-utils/libraries/=src/").unwrap().into(), + ]; + let proj_toml_file = prj.paths().root.join("foundry.toml"); + pretty_err(&proj_toml_file, fs::write(&proj_toml_file, config.to_string_pretty().unwrap())); + + // Create a new lib in the `lib` folder with conflicting `@utils/libraries` remapping. + // This should be filtered out from final remappings as root project already has `@utils/`. + let nested = prj.paths().libraries[0].join("dep1"); + pretty_err(&nested, fs::create_dir_all(&nested)); + let mut lib_config = Config::load_with_root(&nested); + lib_config.remappings = vec![ + Remapping::from_str("@utils/libraries/=src/").unwrap().into(), + Remapping::from_str("@another-utils/=src/").unwrap().into(), + ]; + let lib_toml_file = nested.join("foundry.toml"); + pretty_err(&lib_toml_file, fs::write(&lib_toml_file, lib_config.to_string_pretty().unwrap())); + + cmd.args(["remappings", "--pretty"]).assert_success().stdout_eq(str![[r#" +Global: +- @utils/=src/ +- @another-utils/libraries/=src/ +- @another-utils/=lib/dep1/src/ +- dep1/=lib/dep1/src/ +- forge-std/=lib/forge-std/src/ + + +"#]]); +}); + // test to check that foundry.toml libs section updates on install forgetest!(can_update_libs_section, |prj, cmd| { cmd.git_init(); @@ -653,7 +691,7 @@ Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std fs::write(prj.root().join("lib").join("forge-std").join("foundry.toml"), faulty_toml).unwrap(); cmd.forge_fuse().args(["config"]).assert_success().stderr_eq(str![[r#" -warning: Found unknown config section in foundry.toml: [default] +Warning: Found unknown config section in foundry.toml: [default] This notation for profiles has been deprecated and may result in the profile not being registered in future versions. Please use [profile.default] instead or run `forge config --fix`. diff --git a/crates/forge/tests/cli/debug.rs b/crates/forge/tests/cli/debug.rs index bbed7dc72..e8cd08418 100644 --- a/crates/forge/tests/cli/debug.rs +++ b/crates/forge/tests/cli/debug.rs @@ -7,13 +7,20 @@ forgetest_async!( #[ignore = "ran manually"] manual_debug_setup, |prj, cmd| { - cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" -Target directory is not empty, but `--force` was specified + cmd.args(["init", "--force"]) + .arg(prj.root()) + .assert_success() + .stdout_eq(str![[r#" Initializing [..]... Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) Installed forge-std[..] Initialized forge project +"#]]) + .stderr_eq(str![[r#" +Warning: Target directory is not empty, but `--force` was specified +... + "#]]); prj.add_source("Counter2.sol", r#" diff --git a/crates/forge/tests/cli/main.rs b/crates/forge/tests/cli/main.rs index 6ad29ca48..a53a26d2a 100644 --- a/crates/forge/tests/cli/main.rs +++ b/crates/forge/tests/cli/main.rs @@ -9,6 +9,7 @@ mod bind_json; mod build; mod cache; mod cmd; +mod compiler; mod config; mod context; mod coverage; diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 38f8f9479..4b4e89bdd 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -3,6 +3,7 @@ use crate::constants::TEMPLATE_CONTRACT; use alloy_primitives::{hex, Address, Bytes}; use anvil::{spawn, NodeConfig}; +use forge_script_sequence::ScriptSequence; use foundry_test_utils::{ rpc, util::{OutputExt, OTHER_SOLC_VERSION, SOLC_VERSION}, @@ -150,8 +151,7 @@ forgetest_async!(assert_exit_code_error_on_failure_script, |prj, cmd| { // run command and assert error exit code cmd.assert_failure().stderr_eq(str![[r#" -Error: -script failed: revert: failed +Error: script failed: revert: failed "#]]); }); @@ -167,8 +167,7 @@ forgetest_async!(assert_exit_code_error_on_failure_script_with_json, |prj, cmd| // run command and assert error exit code cmd.assert_failure().stderr_eq(str![[r#" -Error: -script failed: revert: failed +Error: script failed: revert: failed "#]]); }); @@ -201,7 +200,7 @@ contract DeployScript is Script { let deploy_contract = deploy_script.display().to_string() + ":DeployScript"; let node_config = - NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_endpoint())).silent(); + NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_endpoint())); let (_api, handle) = spawn(node_config).await; let dev = handle.dev_accounts().next().unwrap(); cmd.set_current_dir(prj.root()); @@ -303,7 +302,7 @@ contract DeployScript is Script { let deploy_contract = deploy_script.display().to_string() + ":DeployScript"; let node_config = - NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_endpoint())).silent(); + NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_endpoint())); let (_api, handle) = spawn(node_config).await; let private_key = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".to_string(); @@ -493,7 +492,7 @@ contract DeployScript is Script { let deploy_contract = deploy_script.display().to_string() + ":DeployScript"; let node_config = - NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_endpoint())).silent(); + NodeConfig::test().with_eth_rpc_url(Some(rpc::next_http_archive_rpc_endpoint())); let (_api, handle) = spawn(node_config).await; let private_key = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".to_string(); @@ -1012,13 +1011,20 @@ struct Transaction { // test we output arguments forgetest_async!(can_execute_script_with_arguments, |prj, cmd| { - cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" -Target directory is not empty, but `--force` was specified + cmd.args(["init", "--force"]) + .arg(prj.root()) + .assert_success() + .stdout_eq(str![[r#" Initializing [..]... Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) Installed forge-std[..] Initialized forge project +"#]]) + .stderr_eq(str![[r#" +Warning: Target directory is not empty, but `--force` was specified +... + "#]]); let (_api, handle) = spawn(NodeConfig::test()).await; @@ -1134,13 +1140,20 @@ SIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet // test we output arguments forgetest_async!(can_execute_script_with_arguments_nested_deploy, |prj, cmd| { - cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" -Target directory is not empty, but `--force` was specified + cmd.args(["init", "--force"]) + .arg(prj.root()) + .assert_success() + .stdout_eq(str![[r#" Initializing [..]... Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) Installed forge-std[..] Initialized forge project +"#]]) + .stderr_eq(str![[r#" +Warning: Target directory is not empty, but `--force` was specified +... + "#]]); let (_api, handle) = spawn(NodeConfig::test()).await; @@ -1301,13 +1314,20 @@ forgetest_async!(does_script_override_correctly, |prj, cmd| { }); forgetest_async!(assert_tx_origin_is_not_overritten, |prj, cmd| { - cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" -Target directory is not empty, but `--force` was specified + cmd.args(["init", "--force"]) + .arg(prj.root()) + .assert_success() + .stdout_eq(str![[r#" Initializing [..]... Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) Installed forge-std[..] Initialized forge project +"#]]) + .stderr_eq(str![[r#" +Warning: Target directory is not empty, but `--force` was specified +... + "#]]); let script = prj @@ -1382,13 +1402,20 @@ If you wish to simulate on-chain transactions pass a RPC URL. }); forgetest_async!(assert_can_create_multiple_contracts_with_correct_nonce, |prj, cmd| { - cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" -Target directory is not empty, but `--force` was specified + cmd.args(["init", "--force"]) + .arg(prj.root()) + .assert_success() + .stdout_eq(str![[r#" Initializing [..]... Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) Installed forge-std[..] Initialized forge project +"#]]) + .stderr_eq(str![[r#" +Warning: Target directory is not empty, but `--force` was specified +... + "#]]); let script = prj @@ -1609,20 +1636,26 @@ contract Script { cmd.arg("script").args([&script.to_string_lossy(), "--sig", "run"]); cmd.assert_failure().stderr_eq(str![[r#" -Error: -Multiple functions with the same name `run` found in the ABI +Error: Multiple functions with the same name `run` found in the ABI "#]]); }); forgetest_async!(can_decode_custom_errors, |prj, cmd| { - cmd.args(["init", "--force"]).arg(prj.root()).assert_success().stdout_eq(str![[r#" -Target directory is not empty, but `--force` was specified + cmd.args(["init", "--force"]) + .arg(prj.root()) + .assert_success() + .stdout_eq(str![[r#" Initializing [..]... Installing forge-std in [..] (url: Some("https://github.com/foundry-rs/forge-std"), tag: None) Installed forge-std[..] Initialized forge project +"#]]) + .stderr_eq(str![[r#" +Warning: Target directory is not empty, but `--force` was specified +... + "#]]); let script = prj @@ -1652,8 +1685,7 @@ contract CustomErrorScript is Script { cmd.forge_fuse().arg("script").arg(script).args(["--tc", "CustomErrorScript"]); cmd.assert_failure().stderr_eq(str![[r#" -Error: -script failed: CustomError() +Error: script failed: CustomError() "#]]); }); @@ -1709,7 +1741,6 @@ Script ran successfully. success: bool true ## Setting up 1 EVM. -Script contains a transaction to 0x0000000000000000000000000000000000000000 which does not contain any code. ========================== @@ -1733,6 +1764,9 @@ ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. [SAVED_SENSITIVE_VALUES] +"#]]).stderr_eq(str![[r#" +Warning: Script contains a transaction to 0x0000000000000000000000000000000000000000 which does not contain any code. + "#]]); // Ensure that we can correctly estimate gas when base fee is zero but priority fee is not. @@ -1758,7 +1792,6 @@ Script ran successfully. success: bool true ## Setting up 1 EVM. -Script contains a transaction to 0x0000000000000000000000000000000000000000 which does not contain any code. ========================== @@ -1782,6 +1815,9 @@ ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. [SAVED_SENSITIVE_VALUES] +"#]]).stderr_eq(str![[r#" +Warning: Script contains a transaction to 0x0000000000000000000000000000000000000000 which does not contain any code. + "#]]); }); @@ -1826,7 +1862,6 @@ Script ran successfully. success: bool true ## Setting up 1 EVM. -Script contains a transaction to 0x0000000000000000000000000000000000000000 which does not contain any code. ========================== @@ -1850,6 +1885,9 @@ ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. [SAVED_SENSITIVE_VALUES] +"#]]).stderr_eq(str![[r#" +Warning: Script contains a transaction to 0x0000000000000000000000000000000000000000 which does not contain any code. + "#]]); }); @@ -1886,8 +1924,7 @@ contract SimpleScript is Script { ]); cmd.assert_failure().stderr_eq(str![[r#" -Error: -script failed: missing CREATE2 deployer +Error: script failed: missing CREATE2 deployer "#]]); }); @@ -2254,3 +2291,141 @@ Script ran successfully. "#]]); }); + +forgetest_async!(can_simulate_with_default_sender, |prj, cmd| { + let (_api, handle) = spawn(NodeConfig::test()).await; + + foundry_test_utils::util::initialize(prj.root()); + prj.add_script( + "Script.s.sol", + r#" +import "forge-std/Script.sol"; +contract A { + function getValue() external pure returns (uint256) { + return 100; + } +} +contract B { + constructor(A a) { + require(a.getValue() == 100); + } +} +contract SimpleScript is Script { + function run() external { + vm.startBroadcast(); + A a = new A(); + new B(a); + } +} + "#, + ) + .unwrap(); + + cmd.arg("script").args(["SimpleScript", "--fork-url", &handle.http_endpoint(), "-vvvv"]); + cmd.assert_success().stdout_eq(str![[r#" +[COMPILING_FILES] with [SOLC_VERSION] +[SOLC_VERSION] [ELAPSED] +Compiler run successful! +Traces: + [104553] SimpleScript::run() + ├─ [0] VM::startBroadcast() + │ └─ ← [Return] + ├─ [23875] → new A@0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519 + │ └─ ← [Return] 119 bytes of code + ├─ [13367] → new B@0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 + │ ├─ [146] A::getValue() [staticcall] + │ │ └─ ← [Return] 100 + │ └─ ← [Return] 63 bytes of code + └─ ← [Stop] + + +Script ran successfully. + +## Setting up 1 EVM. +========================== +Simulated On-chain Traces: + + [23875] → new A@0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519 + └─ ← [Return] 119 bytes of code + + [15867] → new B@0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496 + ├─ [146] A::getValue() [staticcall] + │ └─ ← [Return] 100 + └─ ← [Return] 63 bytes of code +... +"#]]); +}); + +// Tests that chained errors are properly displayed. +// +forgetest_init!( + #[ignore] + should_display_evm_chained_error, + |prj, cmd| { + let script = prj + .add_source( + "Foo", + r#" +import "forge-std/Script.sol"; + +contract ContractScript is Script { + function run() public { + } +} + "#, + ) + .unwrap(); + cmd.arg("script").arg(script).args(["--fork-url", "https://public-node.testnet.rsk.co"]).assert_failure().stderr_eq(str![[r#" +Error: Failed to deploy script: +backend: failed while inspecting; header validation error: `prevrandao` not set; `prevrandao` not set; + +"#]]); + } +); + +forgetest_async!(should_detect_additional_contracts, |prj, cmd| { + let (_api, handle) = spawn(NodeConfig::test()).await; + + foundry_test_utils::util::initialize(prj.root()); + prj.add_source( + "Foo", + r#" +import "forge-std/Script.sol"; + +contract Simple {} + +contract Deployer { + function deploy() public { + new Simple(); + } +} + +contract ContractScript is Script { + function run() public { + vm.startBroadcast(); + Deployer deployer = new Deployer(); + deployer.deploy(); + } +} + "#, + ) + .unwrap(); + cmd.arg("script") + .args([ + "ContractScript", + "--private-key", + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "--rpc-url", + &handle.http_endpoint(), + ]) + .assert_success(); + + let run_latest = foundry_common::fs::json_files(&prj.root().join("broadcast")) + .find(|file| file.ends_with("run-latest.json")) + .expect("No broadcast artifacts"); + + let sequence: ScriptSequence = foundry_common::fs::read_json_file(&run_latest).unwrap(); + + assert_eq!(sequence.transactions.len(), 2); + assert_eq!(sequence.transactions[1].additional_contracts.len(), 1); +}); diff --git a/crates/forge/tests/cli/test_cmd.rs b/crates/forge/tests/cli/test_cmd.rs index d9eee082b..9381a7d05 100644 --- a/crates/forge/tests/cli/test_cmd.rs +++ b/crates/forge/tests/cli/test_cmd.rs @@ -1,6 +1,7 @@ //! Contains various tests for `forge test`. use alloy_primitives::U256; +use anvil::{spawn, NodeConfig}; use foundry_config::{Config, FuzzConfig}; use foundry_test_utils::{ rpc, str, @@ -2225,22 +2226,19 @@ Warning: the following cheatcode(s) are deprecated and will be removed in future forgetest_init!(requires_single_test, |prj, cmd| { cmd.args(["test", "--debug"]).assert_failure().stderr_eq(str![[r#" -Error: -2 tests matched your criteria, but exactly 1 test must match in order to run the debugger. +Error: 2 tests matched your criteria, but exactly 1 test must match in order to run the debugger. Use --match-contract and --match-path to further limit the search. "#]]); cmd.forge_fuse().args(["test", "--flamegraph"]).assert_failure().stderr_eq(str![[r#" -Error: -2 tests matched your criteria, but exactly 1 test must match in order to generate a flamegraph. +Error: 2 tests matched your criteria, but exactly 1 test must match in order to generate a flamegraph. Use --match-contract and --match-path to further limit the search. "#]]); cmd.forge_fuse().args(["test", "--flamechart"]).assert_failure().stderr_eq(str![[r#" -Error: -2 tests matched your criteria, but exactly 1 test must match in order to generate a flamechart. +Error: 2 tests matched your criteria, but exactly 1 test must match in order to generate a flamechart. Use --match-contract and --match-path to further limit the search. @@ -2249,7 +2247,7 @@ Use --match-contract and --match-path to further limit the search. forgetest_init!(deprecated_regex_arg, |prj, cmd| { cmd.args(["test", "--decode-internal", "test_Increment"]).assert_success().stderr_eq(str![[r#" -warning: specifying argument for --decode-internal is deprecated and will be removed in the future, use --match-test instead +Warning: specifying argument for --decode-internal is deprecated and will be removed in the future, use --match-test instead "#]]); }); @@ -2407,3 +2405,224 @@ Ran 1 test suite [ELAPSED]: 1 tests passed, 0 failed, 0 skipped (1 total tests) "#]]); }); + +// Tests if dump of execution was created. +forgetest!(test_debug_with_dump, |prj, cmd| { + prj.add_source( + "dummy", + r" +contract Dummy { + function testDummy() public {} +} +", + ) + .unwrap(); + + let dump_path = prj.root().join("dump.json"); + + cmd.args(["test", "--debug", "testDummy", "--dump", dump_path.to_str().unwrap()]); + cmd.assert_success(); + + assert!(dump_path.exists()); +}); + +forgetest_async!(can_get_broadcast_txs, |prj, cmd| { + foundry_test_utils::util::initialize(prj.root()); + + let (_api, handle) = spawn(NodeConfig::test().silent()).await; + + prj.insert_vm(); + prj.insert_ds_test(); + prj.insert_console(); + + prj.add_source( + "Counter.sol", + r#" + contract Counter { + uint256 public number; + + function setNumber(uint256 newNumber) public { + number = newNumber; + } + + function increment() public { + number++; + } +} + "#, + ) + .unwrap(); + + prj.add_script( + "DeployCounter", + r#" + import "forge-std/Script.sol"; + import "src/Counter.sol"; + + contract DeployCounter is Script { + function run() public { + vm.startBroadcast(); + + Counter counter = new Counter(); + + counter.increment(); + + counter.setNumber(10); + + vm.stopBroadcast(); + } + } + "#, + ) + .unwrap(); + + prj.add_script( + "DeployCounterWithCreate2", + r#" + import "forge-std/Script.sol"; + import "src/Counter.sol"; + + contract DeployCounterWithCreate2 is Script { + function run() public { + vm.startBroadcast(); + + bytes32 salt = bytes32(uint256(1337)); + Counter counter = new Counter{salt: salt}(); + + counter.increment(); + + counter.setNumber(20); + + vm.stopBroadcast(); + } + } + "#, + ) + .unwrap(); + + let test = r#" + import {Vm} from "../src/Vm.sol"; + import {DSTest} from "../src/test.sol"; + import {console} from "../src/console.sol"; + + contract GetBroadcastTest is DSTest { + + Vm constant vm = Vm(HEVM_ADDRESS); + + function test_getLatestBroacast() external { + // Gets the latest create + Vm.BroadcastTxSummary memory broadcast = vm.getBroadcast( + "Counter", + 31337, + Vm.BroadcastTxType.Create + ); + + console.log("latest create"); + console.log(broadcast.blockNumber); + + assertEq(broadcast.blockNumber, 1); + + // Gets the latest create2 + Vm.BroadcastTxSummary memory broadcast2 = vm.getBroadcast( + "Counter", + 31337, + Vm.BroadcastTxType.Create2 + ); + + console.log("latest create2"); + console.log(broadcast2.blockNumber); + assertEq(broadcast2.blockNumber, 4); + + // Gets the latest call + Vm.BroadcastTxSummary memory broadcast3 = vm.getBroadcast( + "Counter", + 31337, + Vm.BroadcastTxType.Call + ); + + console.log("latest call"); + assertEq(broadcast3.blockNumber, 6); + } + + function test_getBroadcasts() public { + // Gets all calls + Vm.BroadcastTxSummary[] memory broadcasts = vm.getBroadcasts( + "Counter", + 31337, + Vm.BroadcastTxType.Call + ); + + assertEq(broadcasts.length, 4); + } + + function test_getAllBroadcasts() public { + // Gets all broadcasts + Vm.BroadcastTxSummary[] memory broadcasts2 = vm.getBroadcasts( + "Counter", + 31337 + ); + + assertEq(broadcasts2.length, 6); + } + + function test_getLatestDeployment() public { + address deployedAddress = vm.getDeployment( + "Counter", + 31337 + ); + + assertEq(deployedAddress, address(0x030D07c16e2c0a77f74ab16f3C8F10ACeF89FF81)); + } + + function test_getDeployments() public { + address[] memory deployments = vm.getDeployments( + "Counter", + 31337 + ); + + assertEq(deployments.length, 2); + assertEq(deployments[0], address(0x030D07c16e2c0a77f74ab16f3C8F10ACeF89FF81)); // Create2 address - latest deployment + assertEq(deployments[1], address(0x5FbDB2315678afecb367f032d93F642f64180aa3)); // Create address - oldest deployment + } + +} + "#; + + prj.add_test("GetBroadcast", test).unwrap(); + + let sender = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; + + cmd.args([ + "script", + "DeployCounter", + "--rpc-url", + &handle.http_endpoint(), + "--sender", + sender, + "--unlocked", + "--broadcast", + "--slow", + ]) + .assert_success(); + + cmd.forge_fuse() + .args([ + "script", + "DeployCounterWithCreate2", + "--rpc-url", + &handle.http_endpoint(), + "--sender", + sender, + "--unlocked", + "--broadcast", + "--slow", + ]) + .assert_success(); + + let broadcast_path = prj.root().join("broadcast"); + + // Check if the broadcast folder exists + assert!(broadcast_path.exists() && broadcast_path.is_dir()); + + cmd.forge_fuse().args(["test", "--mc", "GetBroadcastTest", "-vvv"]).assert_success(); +}); diff --git a/crates/forge/tests/cli/utils.rs b/crates/forge/tests/cli/utils.rs index 094255195..2b0bb6273 100644 --- a/crates/forge/tests/cli/utils.rs +++ b/crates/forge/tests/cli/utils.rs @@ -126,7 +126,7 @@ impl EnvExternalities { pub fn parse_deployed_address(out: &str) -> Option { for line in out.lines() { if line.starts_with("Deployed to") { - return Some(line.trim_start_matches("Deployed to: ").to_string()) + return Some(line.trim_start_matches("Deployed to: ").to_string()); } } None @@ -135,8 +135,33 @@ pub fn parse_deployed_address(out: &str) -> Option { pub fn parse_verification_guid(out: &str) -> Option { for line in out.lines() { if line.contains("GUID") { - return Some(line.replace("GUID:", "").replace('`', "").trim().to_string()) + return Some(line.replace("GUID:", "").replace('`', "").trim().to_string()); } } None } + +// Generates a string containing the code of a Solidity contract +// with a variable init code size. +pub fn generate_large_contract(num_elements: usize) -> String { + let mut contract_code = String::new(); + + contract_code.push_str( + "// Auto-generated Solidity contract to inflate initcode size\ncontract HugeContract {\n uint256 public number;\n" + ); + + contract_code.push_str(" uint256[] public largeArray;\n\n constructor() {\n"); + contract_code.push_str(" largeArray = ["); + + for i in 0..num_elements { + if i != 0 { + contract_code.push_str(", "); + } + contract_code.push_str(&i.to_string()); + } + + contract_code.push_str("];\n"); + contract_code.push_str(" }\n}"); + + contract_code +} diff --git a/crates/forge/tests/cli/verify.rs b/crates/forge/tests/cli/verify.rs index c8ce2c25f..154c74e30 100644 --- a/crates/forge/tests/cli/verify.rs +++ b/crates/forge/tests/cli/verify.rs @@ -73,6 +73,7 @@ contract Verify is Unique { .unwrap(); } +#[allow(clippy::disallowed_macros)] fn parse_verification_result(cmd: &mut TestCommand, retries: u32) -> eyre::Result<()> { // give etherscan some time to verify the contract let retry = Retry::new(retries, Some(Duration::from_secs(30))); @@ -124,6 +125,7 @@ fn await_verification_response(info: EnvExternalities, mut cmd: TestCommand) { parse_verification_result(&mut cmd, 6).expect("Failed to verify check") } +#[allow(clippy::disallowed_macros)] fn verify_on_chain(info: Option, prj: TestProject, mut cmd: TestCommand) { // only execute if keys present if let Some(info) = info { @@ -157,6 +159,7 @@ fn verify_on_chain(info: Option, prj: TestProject, mut cmd: Te } } +#[allow(clippy::disallowed_macros)] fn guess_constructor_args(info: Option, prj: TestProject, mut cmd: TestCommand) { // only execute if keys present if let Some(info) = info { @@ -197,6 +200,7 @@ fn guess_constructor_args(info: Option, prj: TestProject, mut } } +#[allow(clippy::disallowed_macros)] /// Executes create --verify on the given chain fn create_verify_on_chain(info: Option, prj: TestProject, mut cmd: TestCommand) { // only execute if keys present diff --git a/crates/forge/tests/it/invariant.rs b/crates/forge/tests/it/invariant.rs index 37b3c9b23..3e09cd465 100644 --- a/crates/forge/tests/it/invariant.rs +++ b/crates/forge/tests/it/invariant.rs @@ -855,3 +855,76 @@ contract NoSelectorTest is Test { ... "#]]); }); + +// +forgetest_init!(should_show_invariant_metrics, |prj, cmd| { + prj.add_test( + "SelectorMetricsTest.t.sol", + r#" +import {Test} from "forge-std/Test.sol"; + +contract CounterTest is Test { + function setUp() public { + CounterHandler handler = new CounterHandler(); + AnotherCounterHandler handler1 = new AnotherCounterHandler(); + // targetContract(address(handler1)); + } + + /// forge-config: default.invariant.runs = 10 + /// forge-config: default.invariant.show-metrics = true + function invariant_counter() public {} + + /// forge-config: default.invariant.runs = 10 + /// forge-config: default.invariant.show-metrics = true + function invariant_counter2() public {} +} + +contract CounterHandler is Test { + function doSomething(uint256 a) public { + vm.assume(a < 10_000_000); + require(a < 100_000); + } + + function doAnotherThing(uint256 a) public { + vm.assume(a < 10_000_000); + require(a < 100_000); + } +} + +contract AnotherCounterHandler is Test { + function doWork(uint256 a) public { + vm.assume(a < 10_000_000); + require(a < 100_000); + } + + function doWorkThing(uint256 a) public { + vm.assume(a < 10_000_000); + require(a < 100_000); + } +} + "#, + ) + .unwrap(); + + cmd.args(["test", "--mt", "invariant_"]).assert_success().stdout_eq(str![[r#" +... +Ran 2 tests for test/SelectorMetricsTest.t.sol:CounterTest +[PASS] invariant_counter() (runs: 10, calls: 5000, reverts: [..]) +| Contract | Selector | Calls | Reverts | Discards | +|-----------------------|----------------|-------|---------|----------| +| AnotherCounterHandler | doWork | [..] | [..] | [..] | +| AnotherCounterHandler | doWorkThing | [..] | [..] | [..] | +| CounterHandler | doAnotherThing | [..] | [..] | [..] | +| CounterHandler | doSomething | [..] | [..] | [..] | + +[PASS] invariant_counter2() (runs: 10, calls: 5000, reverts: [..]) +| Contract | Selector | Calls | Reverts | Discards | +|-----------------------|----------------|-------|---------|----------| +| AnotherCounterHandler | doWork | [..] | [..] | [..] | +| AnotherCounterHandler | doWorkThing | [..] | [..] | [..] | +| CounterHandler | doAnotherThing | [..] | [..] | [..] | +| CounterHandler | doSomething | [..] | [..] | [..] | + +... +"#]]); +}); diff --git a/crates/forge/tests/it/test_helpers.rs b/crates/forge/tests/it/test_helpers.rs index ebce7b3f1..8f1a3ad07 100644 --- a/crates/forge/tests/it/test_helpers.rs +++ b/crates/forge/tests/it/test_helpers.rs @@ -142,6 +142,7 @@ impl ForgeTestProfile { max_assume_rejects: 65536, gas_report_samples: 256, failure_persist_dir: Some(tempfile::tempdir().unwrap().into_path()), + show_metrics: false, no_zksync_reserved_addresses: false, }) .build(output, Path::new(self.project().root())) diff --git a/crates/script-sequence/Cargo.toml b/crates/script-sequence/Cargo.toml index 4b63dc1fe..aadf03bae 100644 --- a/crates/script-sequence/Cargo.toml +++ b/crates/script-sequence/Cargo.toml @@ -23,6 +23,7 @@ serde.workspace = true eyre.workspace = true serde_json.workspace = true tracing.workspace = true +walkdir.workspace = true revm-inspectors.workspace = true diff --git a/crates/script-sequence/src/lib.rs b/crates/script-sequence/src/lib.rs index 3aa5fc65a..929f44a72 100644 --- a/crates/script-sequence/src/lib.rs +++ b/crates/script-sequence/src/lib.rs @@ -1,7 +1,12 @@ //! Script Sequence and related types. +#[macro_use] +extern crate foundry_common; + +pub mod reader; pub mod sequence; pub mod transaction; +pub use reader::*; pub use sequence::*; pub use transaction::*; diff --git a/crates/script-sequence/src/reader.rs b/crates/script-sequence/src/reader.rs new file mode 100644 index 000000000..c4627dec0 --- /dev/null +++ b/crates/script-sequence/src/reader.rs @@ -0,0 +1,179 @@ +use crate::{ScriptSequence, TransactionWithMetadata}; +use alloy_rpc_types::AnyTransactionReceipt; +use eyre::{bail, Result}; +use foundry_common::fs; +use revm_inspectors::tracing::types::CallKind; +use std::path::{Component, Path, PathBuf}; + +/// This type reads broadcast files in the +/// `project_root/broadcast/{contract_name}.s.sol/{chain_id}/` directory. +/// +/// It consists methods that filter and search for transactions in the broadcast files that match a +/// `transactionType` if provided. +/// +/// Note: +/// +/// It only returns transactions for which there exists a corresponding receipt in the broadcast. +#[derive(Debug, Clone)] +pub struct BroadcastReader { + contract_name: String, + chain_id: u64, + tx_type: Vec, + broadcast_path: PathBuf, +} + +impl BroadcastReader { + /// Create a new `BroadcastReader` instance. + pub fn new(contract_name: String, chain_id: u64, broadcast_path: &Path) -> Result { + if !broadcast_path.exists() && !broadcast_path.is_dir() { + bail!("broadcast dir does not exist"); + } + + Ok(Self { + contract_name, + chain_id, + tx_type: Default::default(), + broadcast_path: broadcast_path.to_path_buf(), + }) + } + + /// Set the transaction type to filter by. + pub fn with_tx_type(mut self, tx_type: CallKind) -> Self { + self.tx_type.push(tx_type); + self + } + + /// Read all broadcast files in the broadcast directory. + /// + /// Example structure: + /// + /// project-root/broadcast/{script_name}.s.sol/{chain_id}/*.json + /// project-root/broadcast/multi/{multichain_script_name}.s.sol-{timestamp}/deploy.json + pub fn read(&self) -> eyre::Result> { + // 1. Recursively read all .json files in the broadcast directory + let mut broadcasts = vec![]; + for entry in walkdir::WalkDir::new(&self.broadcast_path).into_iter() { + let entry = entry?; + let path = entry.path(); + + if path.is_file() && path.extension().is_some_and(|ext| ext == "json") { + // Ignore -latest to avoid duplicating broadcast entries + if path.components().any(|c| c.as_os_str().to_string_lossy().contains("-latest")) { + continue; + } + + // Detect Multichain broadcasts using "multi" in the path + if path.components().any(|c| c == Component::Normal("multi".as_ref())) { + // Parse as MultiScriptSequence + + let broadcast = fs::read_json_file::(path)?; + let multichain_deployments = broadcast + .get("deployments") + .and_then(|deployments| { + serde_json::from_value::>(deployments.clone()).ok() + }) + .unwrap_or_default(); + + broadcasts.extend(multichain_deployments); + continue; + } + + let broadcast = fs::read_json_file::(path)?; + broadcasts.push(broadcast); + } + } + + let broadcasts = self.filter_and_sort(broadcasts); + + Ok(broadcasts) + } + + /// Attempts read the latest broadcast file in the broadcast directory. + /// + /// This may be the `run-latest.json` file or the broadcast file with the latest timestamp. + pub fn read_latest(&self) -> eyre::Result { + let broadcasts = self.read()?; + + // Find the broadcast with the latest timestamp + let target = broadcasts + .into_iter() + .max_by_key(|broadcast| broadcast.timestamp) + .ok_or_else(|| eyre::eyre!("No broadcasts found"))?; + + Ok(target) + } + + /// Applies the filters and sorts the broadcasts by descending timestamp. + pub fn filter_and_sort(&self, broadcasts: Vec) -> Vec { + // Apply the filters + let mut seqs = broadcasts + .into_iter() + .filter(|broadcast| { + if broadcast.chain != self.chain_id { + return false; + } + + broadcast.transactions.iter().any(move |tx| { + let name_filter = + tx.contract_name.clone().is_some_and(|cn| cn == self.contract_name); + + let type_filter = self.tx_type.is_empty() || + self.tx_type.iter().any(|kind| *kind == tx.opcode); + + name_filter && type_filter + }) + }) + .collect::>(); + + // Sort by descending timestamp + seqs.sort_by(|a, b| b.timestamp.cmp(&a.timestamp)); + + seqs + } + + /// Search for transactions in the broadcast that match the specified `contractName` and + /// `txType`. + /// + /// It cross-checks the transactions with their corresponding receipts in the broadcast and + /// returns the result. + /// + /// Transactions that don't have a corresponding receipt are ignored. + /// + /// Sorts the transactions by descending block number. + pub fn into_tx_receipts( + &self, + broadcast: ScriptSequence, + ) -> Vec<(TransactionWithMetadata, AnyTransactionReceipt)> { + let transactions = broadcast.transactions.clone(); + + let txs = transactions + .into_iter() + .filter(|tx| { + let name_filter = + tx.contract_name.clone().is_some_and(|cn| cn == self.contract_name); + + let type_filter = + self.tx_type.is_empty() || self.tx_type.iter().any(|kind| *kind == tx.opcode); + + name_filter && type_filter + }) + .collect::>(); + + let mut targets = Vec::new(); + for tx in txs.into_iter() { + let maybe_receipt = broadcast + .receipts + .iter() + .find(|receipt| tx.hash.is_some_and(|hash| hash == receipt.transaction_hash)); + + if let Some(receipt) = maybe_receipt { + targets.push((tx, receipt.clone())); + } + } + + // Sort by descending block number + targets.sort_by(|a, b| b.1.block_number.cmp(&a.1.block_number)); + + targets + } +} diff --git a/crates/script-sequence/src/sequence.rs b/crates/script-sequence/src/sequence.rs index 080c725be..e34b6d06a 100644 --- a/crates/script-sequence/src/sequence.rs +++ b/crates/script-sequence/src/sequence.rs @@ -2,7 +2,7 @@ use crate::transaction::TransactionWithMetadata; use alloy_primitives::{hex, map::HashMap, TxHash}; use alloy_rpc_types::AnyTransactionReceipt; use eyre::{ContextCompat, Result, WrapErr}; -use foundry_common::{fs, shell, TransactionMaybeSigned, SELECTOR_LEN}; +use foundry_common::{fs, TransactionMaybeSigned, SELECTOR_LEN}; use foundry_compilers::ArtifactId; use foundry_config::Config; use serde::{Deserialize, Serialize}; @@ -127,8 +127,8 @@ impl ScriptSequence { } if !silent { - shell::println(format!("\nTransactions saved to: {}\n", path.display()))?; - shell::println(format!("Sensitive values saved to: {}\n", sensitive_path.display()))?; + sh_println!("\nTransactions saved to: {}\n", path.display())?; + sh_println!("Sensitive values saved to: {}\n", sensitive_path.display())?; } Ok(()) diff --git a/crates/script/src/broadcast.rs b/crates/script/src/broadcast.rs index 51e912da2..d837abde5 100644 --- a/crates/script/src/broadcast.rs +++ b/crates/script/src/broadcast.rs @@ -21,7 +21,7 @@ use foundry_cheatcodes::Wallets; use foundry_cli::utils::{has_batch_support, has_different_gas_calc}; use foundry_common::{ provider::{get_http_provider, try_get_http_provider, RetryProvider}, - shell, TransactionMaybeSigned, + TransactionMaybeSigned, }; use foundry_config::Config; use foundry_zksync_core::{ @@ -509,8 +509,8 @@ impl BundledState { seq_progress.inner.write().finish(); } - shell::println("\n\n==========================")?; - shell::println("\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.")?; + sh_println!("\n\n==========================")?; + sh_println!("\nONCHAIN EXECUTION COMPLETE & SUCCESSFUL.")?; Ok(BroadcastedState { args: self.args, diff --git a/crates/script/src/build.rs b/crates/script/src/build.rs index 67d95cfab..a82dd994a 100644 --- a/crates/script/src/build.rs +++ b/crates/script/src/build.rs @@ -227,10 +227,7 @@ impl PreprocessedState { ) .chain([target_path.to_path_buf()]); - let output = ProjectCompiler::new() - .quiet_if(args.opts.silent) - .files(sources_to_compile) - .compile(&project)?; + let output = ProjectCompiler::new().files(sources_to_compile).compile(&project)?; let mut zk_output = None; // ZK @@ -244,8 +241,7 @@ impl PreprocessedState { source_files_iter(project.paths.sources.as_path(), SolcLanguage::FILE_EXTENSIONS) .chain([target_path.clone()]); - let zk_compiler = - ProjectCompiler::new().quiet_if(args.opts.silent).files(sources_to_compile); + let zk_compiler = ProjectCompiler::new().files(sources_to_compile); zk_output = Some( zk_compiler diff --git a/crates/script/src/execute.rs b/crates/script/src/execute.rs index 194af7066..8f6e86f41 100644 --- a/crates/script/src/execute.rs +++ b/crates/script/src/execute.rs @@ -19,7 +19,7 @@ use foundry_cli::utils::{ensure_clean_constructor, needs_setup}; use foundry_common::{ fmt::{format_token, format_token_raw}, provider::get_http_provider, - shell, ContractsByArtifact, + ContractsByArtifact, }; use foundry_config::{Config, NamedChain}; use foundry_debugger::Debugger; @@ -34,6 +34,7 @@ use foundry_evm::{ }; use futures::future::join_all; use itertools::Itertools; +use std::path::PathBuf; use yansi::Paint; /// State after linking, contains the linked build data along with library addresses and optional @@ -197,7 +198,7 @@ impl PreExecutionState { let sender = tx.transaction.from().expect("no sender"); if let Some(ns) = new_sender { if sender != ns { - shell::println("You have more than one deployer who could predeploy libraries. Using `--sender` instead.")?; + sh_warn!("You have more than one deployer who could predeploy libraries. Using `--sender` instead.")?; return Ok(None); } } else if sender != self.script_config.evm_opts.sender { @@ -256,7 +257,7 @@ For more information, please see https://eips.ethereum.org/EIPS/eip-3855", .map(|(_, chain)| *chain as u64) .format(", ") ); - shell::println(msg.yellow())?; + sh_warn!("{}", msg)?; } Ok(()) } @@ -302,10 +303,7 @@ impl ExecutedState { let rpc_data = RpcData::from_transactions(&txs); if rpc_data.is_multi_chain() { - shell::eprintln(format!( - "{}", - "Multi chain deployment is still under development. Use with caution.".yellow() - ))?; + sh_warn!("Multi chain deployment is still under development. Use with caution.")?; if !self.build_data.libraries.is_empty() { eyre::bail!( "Multi chain deployment does not support library linking at the moment." @@ -383,7 +381,7 @@ impl ExecutedState { } } Err(_) => { - shell::println(format!("{returned:?}"))?; + sh_err!("Failed to decode return value: {:x?}", returned)?; } } @@ -401,7 +399,7 @@ impl PreSimulationState { result, }; let json = serde_json::to_string(&json_result)?; - shell::println(json)?; + sh_println!("{json}")?; if !self.execution_result.success { return Err(eyre::eyre!( @@ -424,7 +422,7 @@ impl PreSimulationState { warn!(verbosity, "no traces"); } - shell::println("Traces:")?; + sh_println!("Traces:")?; for (kind, trace) in &result.traces { let should_include = match kind { TraceKind::Setup => verbosity >= 5, @@ -435,22 +433,22 @@ impl PreSimulationState { if should_include { let mut trace = trace.clone(); decode_trace_arena(&mut trace, decoder).await?; - shell::println(render_trace_arena(&trace))?; + sh_println!("{}", render_trace_arena(&trace))?; } } - shell::println(String::new())?; + sh_println!()?; } if result.success { - shell::println(format!("{}", "Script ran successfully.".green()))?; + sh_println!("{}", "Script ran successfully.".green())?; } if self.script_config.evm_opts.fork_url.is_none() { - shell::println(format!("Gas used: {}", result.gas_used))?; + sh_println!("Gas used: {}", result.gas_used)?; } if result.success && !result.returned.is_empty() { - shell::println("\n== Return ==")?; + sh_println!("\n== Return ==")?; match func.abi_decode_output(&result.returned, false) { Ok(decoded) => { for (index, (token, output)) in decoded.iter().zip(&func.outputs).enumerate() { @@ -465,24 +463,24 @@ impl PreSimulationState { } else { index.to_string() }; - shell::println(format!( - "{}: {internal_type} {}", - label.trim_end(), - format_token(token) - ))?; + sh_println!( + "{label}: {internal_type} {value}", + label = label.trim_end(), + value = format_token(token) + )?; } } Err(_) => { - shell::println(format!("{:x?}", (&result.returned)))?; + sh_err!("{:x?}", (&result.returned))?; } } } let console_logs = decode_console_logs(&result.logs); if !console_logs.is_empty() { - shell::println("\n== Logs ==")?; + sh_println!("\n== Logs ==")?; for log in console_logs { - shell::println(format!(" {log}"))?; + sh_println!(" {log}")?; } } @@ -497,7 +495,17 @@ impl PreSimulationState { } pub fn run_debugger(self) -> Result<()> { - let mut debugger = Debugger::builder() + self.create_debugger().try_run_tui()?; + Ok(()) + } + + pub fn run_debug_file_dumper(self, path: &PathBuf) -> Result<()> { + self.create_debugger().dump_to_file(path)?; + Ok(()) + } + + fn create_debugger(self) -> Debugger { + Debugger::builder() .traces( self.execution_result .traces @@ -508,8 +516,6 @@ impl PreSimulationState { .decoder(&self.execution_artifacts.decoder) .sources(self.build_data.sources) .breakpoints(self.execution_result.breakpoints) - .build(); - debugger.try_run()?; - Ok(()) + .build() } } diff --git a/crates/script/src/lib.rs b/crates/script/src/lib.rs index 08b217c95..46b387e20 100644 --- a/crates/script/src/lib.rs +++ b/crates/script/src/lib.rs @@ -5,6 +5,9 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#[macro_use] +extern crate foundry_common; + #[macro_use] extern crate tracing; @@ -52,7 +55,7 @@ use foundry_evm::{ use foundry_wallets::MultiWalletOpts; use foundry_zksync_compiler::DualCompiledContracts; use serde::Serialize; -use yansi::Paint; +use std::path::PathBuf; mod broadcast; mod build; @@ -150,6 +153,15 @@ pub struct ScriptArgs { #[arg(long)] pub debug: bool, + /// Dumps all debugger steps to file. + #[arg( + long, + requires = "debug", + value_hint = ValueHint::FilePath, + value_name = "PATH" + )] + pub dump: Option, + /// Makes sure a transaction is sent, /// only after its previous one has been confirmed and succeeded. #[arg(long)] @@ -169,10 +181,6 @@ pub struct ScriptArgs { #[arg(long)] pub verify: bool, - /// Output results in JSON format. - #[arg(long)] - pub json: bool, - /// Gas price for legacy transactions, or max fee per gas for EIP1559 transactions, either /// specified in wei, or as a string with a unit type. /// @@ -245,10 +253,13 @@ impl ScriptArgs { .await?; if pre_simulation.args.debug { - return pre_simulation.run_debugger() + return match pre_simulation.args.dump.clone() { + Some(ref path) => pre_simulation.run_debug_file_dumper(path), + None => pre_simulation.run_debugger(), + }; } - if pre_simulation.args.json { + if shell::is_json() { pre_simulation.show_json()?; } else { pre_simulation.show_traces().await?; @@ -267,7 +278,7 @@ impl ScriptArgs { // Check if there are any missing RPCs and exit early to avoid hard error. if pre_simulation.execution_artifacts.rpc_data.missing_rpc { - shell::println("\nIf you wish to simulate on-chain transactions pass a RPC URL.")?; + sh_println!("\nIf you wish to simulate on-chain transactions pass a RPC URL.")?; return Ok(()); } @@ -281,7 +292,7 @@ impl ScriptArgs { // Exit early in case user didn't provide any broadcast/verify related flags. if !bundled.args.should_broadcast() { - shell::println("\nSIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet configuration(s) to the previous command. See forge script --help for more.")?; + sh_println!("\nSIMULATION COMPLETE. To broadcast these transactions, add --broadcast and wallet configuration(s) to the previous command. See forge script --help for more.")?; return Ok(()); } @@ -426,12 +437,9 @@ impl ScriptArgs { if deployment_size > max_size { prompt_user = self.should_broadcast(); - shell::println(format!( - "{}", - format!( - "`{name}` is above the contract size limit ({deployment_size} > {max_size})." - ).red() - ))?; + sh_err!( + "`{name}` is above the contract size limit ({deployment_size} > {max_size})." + )?; } } } diff --git a/crates/script/src/multi_sequence.rs b/crates/script/src/multi_sequence.rs index 0aabcf79a..ec2f03ae9 100644 --- a/crates/script/src/multi_sequence.rs +++ b/crates/script/src/multi_sequence.rs @@ -146,8 +146,8 @@ impl MultiChainSequence { } if !silent { - println!("\nTransactions saved to: {}\n", self.path.display()); - println!("Sensitive details saved to: {}\n", self.sensitive_path.display()); + sh_println!("\nTransactions saved to: {}\n", self.path.display())?; + sh_println!("Sensitive details saved to: {}\n", self.sensitive_path.display())?; } Ok(()) diff --git a/crates/script/src/receipts.rs b/crates/script/src/receipts.rs index c1dad5629..af80734c5 100644 --- a/crates/script/src/receipts.rs +++ b/crates/script/src/receipts.rs @@ -1,6 +1,6 @@ use alloy_chains::Chain; use alloy_primitives::{utils::format_units, TxHash, U256}; -use alloy_provider::{PendingTransactionBuilder, Provider}; +use alloy_provider::{PendingTransactionBuilder, PendingTransactionError, Provider, WatchTxError}; use alloy_rpc_types::AnyTransactionReceipt; use eyre::Result; use foundry_common::provider::RetryProvider; @@ -40,12 +40,16 @@ pub async fn check_tx_status( } loop { - if let Ok(receipt) = PendingTransactionBuilder::new(provider, hash) + match PendingTransactionBuilder::new(provider.clone(), hash) .with_timeout(Some(Duration::from_secs(timeout))) .get_receipt() .await { - return Ok(receipt.into()) + Ok(receipt) => return Ok(receipt.into()), + // do nothing on timeout, we will check whether tx is dropped below + Err(PendingTransactionError::TxWatcher(WatchTxError::Timeout)) => {} + // treat other errors as fatal + Err(e) => return Err(e.into()), } if provider.get_transaction_by_hash(hash).await?.is_some() { diff --git a/crates/script/src/runner.rs b/crates/script/src/runner.rs index 94a70eda9..f88c04a9f 100644 --- a/crates/script/src/runner.rs +++ b/crates/script/src/runner.rs @@ -138,6 +138,17 @@ impl ScriptRunner { // construction self.executor.set_balance(address, self.evm_opts.initial_balance)?; + // HACK: if the current sender is the default script sender (which is a default value), we + // set its nonce to a very large value before deploying the script contract. This + // ensures that the nonce increase during this CREATE does not affect deployment + // addresses of contracts that are deployed in the script, Otherwise, we'd have a + // nonce mismatch during script execution and onchain simulation, potentially + // resulting in weird errors like . + let prev_sender_nonce = self.executor.get_nonce(self.evm_opts.sender)?; + if self.evm_opts.sender == CALLER { + self.executor.set_nonce(self.evm_opts.sender, u64::MAX / 2)?; + } + // Deploy an instance of the contract let DeployResult { address, @@ -147,6 +158,10 @@ impl ScriptRunner { .deploy(CALLER, code, U256::ZERO, None) .map_err(|err| eyre::eyre!("Failed to deploy script:\n{}", err))?; + if self.evm_opts.sender == CALLER { + self.executor.set_nonce(self.evm_opts.sender, prev_sender_nonce)?; + } + traces.extend(constructor_traces.map(|traces| (TraceKind::Deployment, traces))); // Optionally call the `setUp` function diff --git a/crates/script/src/simulate.rs b/crates/script/src/simulate.rs index cdeac8572..478f766fa 100644 --- a/crates/script/src/simulate.rs +++ b/crates/script/src/simulate.rs @@ -16,7 +16,7 @@ use eyre::{Context, Result}; use forge_script_sequence::{ScriptSequence, TransactionWithMetadata}; use foundry_cheatcodes::Wallets; use foundry_cli::utils::{has_different_gas_calc, now}; -use foundry_common::{get_contract_name, shell, ContractData}; +use foundry_common::{get_contract_name, ContractData}; use foundry_evm::traces::{decode_trace_arena, render_trace_arena}; use futures::future::{join_all, try_join_all}; use parking_lot::RwLock; @@ -24,7 +24,6 @@ use std::{ collections::{BTreeMap, VecDeque}, sync::Arc, }; -use yansi::Paint; /// Same as [ExecutedState](crate::execute::ExecutedState), but also contains [ExecutionArtifacts] /// which are obtained from [ScriptResult]. @@ -75,7 +74,7 @@ impl PreSimulationState { .collect::>>()?; if self.args.skip_simulation { - shell::println("\nSKIPPING ON CHAIN SIMULATION.")?; + sh_println!("\nSKIPPING ON CHAIN SIMULATION.")?; } else { transactions = self.simulate_and_fill(transactions).await?; } @@ -113,11 +112,11 @@ impl PreSimulationState { // Executes all transactions from the different forks concurrently. let futs = transactions .into_iter() - .map(|mut transaction| async { + .map(|transaction| async { let mut runner = runners.get(&transaction.rpc).expect("invalid rpc url").write(); let zk_metadata = transaction.zk.clone(); - let tx = transaction.tx_mut(); + let tx = transaction.tx(); let to = if let Some(TxKind::Call(to)) = tx.to() { Some(to) } else { None }; let result = runner .simulate( @@ -173,7 +172,9 @@ impl PreSimulationState { if let Some(tx) = tx { if is_noop_tx { let to = tx.contract_address.unwrap(); - shell::println(format!("Script contains a transaction to {to} which does not contain any code.").yellow())?; + sh_warn!( + "Script contains a transaction to {to} which does not contain any code." + )?; // Only prompt if we're broadcasting and we've not disabled interactivity. if self.args.should_broadcast() && @@ -220,11 +221,10 @@ impl PreSimulationState { /// Build [ScriptRunner] forking given RPC for each RPC used in the script. async fn build_runners(&self) -> Result> { let rpcs = self.execution_artifacts.rpc_data.total_rpcs.clone(); - if !shell::verbosity().is_silent() { - let n = rpcs.len(); - let s = if n != 1 { "s" } else { "" }; - println!("\n## Setting up {n} EVM{s}."); - } + + let n = rpcs.len(); + let s = if n != 1 { "s" } else { "" }; + sh_println!("\n## Setting up {n} EVM{s}.")?; let futs = rpcs.into_iter().map(|rpc| async move { let mut script_config = self.script_config.clone(); @@ -350,24 +350,24 @@ impl FilledTransactionsState { provider_info.gas_price()? }; - shell::println("\n==========================")?; - shell::println(format!("\nChain {}", provider_info.chain))?; + sh_println!("\n==========================")?; + sh_println!("\nChain {}", provider_info.chain)?; - shell::println(format!( + sh_println!( "\nEstimated gas price: {} gwei", format_units(per_gas, 9) .unwrap_or_else(|_| "[Could not calculate]".to_string()) .trim_end_matches('0') .trim_end_matches('.') - ))?; - shell::println(format!("\nEstimated total gas used for script: {total_gas}"))?; - shell::println(format!( + )?; + sh_println!("\nEstimated total gas used for script: {total_gas}")?; + sh_println!( "\nEstimated amount required: {} ETH", format_units(total_gas.saturating_mul(per_gas), 18) .unwrap_or_else(|_| "[Could not calculate]".to_string()) .trim_end_matches('0') - ))?; - shell::println("\n==========================")?; + )?; + sh_println!("\n==========================")?; } } diff --git a/crates/script/src/transaction.rs b/crates/script/src/transaction.rs index 3e14e24ef..87bcdec56 100644 --- a/crates/script/src/transaction.rs +++ b/crates/script/src/transaction.rs @@ -161,6 +161,8 @@ impl ScriptTransactionBuilder { self.transaction.contract_address.map_or(true, |addr| addr != contract.address) }); + self.transaction.additional_contracts = created_contracts; + if !self.transaction.is_fixed_gas_limit { if let Some(unsigned) = self.transaction.transaction.as_unsigned_mut() { // We inflate the gas used by the user specified percentage diff --git a/crates/test-utils/src/macros.rs b/crates/test-utils/src/macros.rs index cc92bb040..08900ad14 100644 --- a/crates/test-utils/src/macros.rs +++ b/crates/test-utils/src/macros.rs @@ -37,6 +37,7 @@ macro_rules! forgetest { $crate::forgetest!($(#[$attr])* $test, $crate::foundry_compilers::PathStyle::Dapptools, |$prj, $cmd| $e); }; ($(#[$attr:meta])* $test:ident, $style:expr, |$prj:ident, $cmd:ident| $e:expr) => { + #[allow(clippy::disallowed_macros)] #[test] $(#[$attr])* fn $test() { @@ -52,6 +53,7 @@ macro_rules! forgetest_async { $crate::forgetest_async!($(#[$attr])* $test, $crate::foundry_compilers::PathStyle::Dapptools, |$prj, $cmd| $e); }; ($(#[$attr:meta])* $test:ident, $style:expr, |$prj:ident, $cmd:ident| $e:expr) => { + #[allow(clippy::disallowed_macros)] #[tokio::test(flavor = "multi_thread")] $(#[$attr])* async fn $test() { @@ -67,6 +69,7 @@ macro_rules! casttest { $crate::casttest!($(#[$attr])* $test, $crate::foundry_compilers::PathStyle::Dapptools, $($async)? |$prj, $cmd| $e); }; ($(#[$attr:meta])* $test:ident, $style:expr, |$prj:ident, $cmd:ident| $e:expr) => { + #[allow(clippy::disallowed_macros)] #[test] $(#[$attr])* fn $test() { @@ -75,6 +78,7 @@ macro_rules! casttest { } }; ($(#[$attr:meta])* $test:ident, $style:expr, async |$prj:ident, $cmd:ident| $e:expr) => { + #[allow(clippy::disallowed_macros)] #[tokio::test(flavor = "multi_thread")] $(#[$attr])* async fn $test() { @@ -86,11 +90,13 @@ macro_rules! casttest { /// Same as `forgetest` but returns an already initialized project workspace (`forge init`) #[macro_export] +#[allow(clippy::disallowed_macros)] macro_rules! forgetest_init { ($(#[$attr:meta])* $test:ident, |$prj:ident, $cmd:ident| $e:expr) => { $crate::forgetest_init!($(#[$attr])* $test, $crate::foundry_compilers::PathStyle::Dapptools, |$prj, $cmd| $e); }; ($(#[$attr:meta])* $test:ident, $style:expr, |$prj:ident, $cmd:ident| $e:expr) => { + #[allow(clippy::disallowed_macros)] #[test] $(#[$attr])* fn $test() { @@ -103,11 +109,13 @@ macro_rules! forgetest_init { /// Setup forge soldeer #[macro_export] +#[allow(clippy::disallowed_macros)] macro_rules! forgesoldeer { ($(#[$attr:meta])* $test:ident, |$prj:ident, $cmd:ident| $e:expr) => { $crate::forgesoldeer!($(#[$attr])* $test, $crate::foundry_compilers::PathStyle::Dapptools, |$prj, $cmd| $e); }; ($(#[$attr:meta])* $test:ident, $style:expr, |$prj:ident, $cmd:ident| $e:expr) => { + #[allow(clippy::disallowed_macros)] #[test] $(#[$attr])* fn $test() { diff --git a/crates/test-utils/src/script.rs b/crates/test-utils/src/script.rs index 9b0185732..f15e91d5a 100644 --- a/crates/test-utils/src/script.rs +++ b/crates/test-utils/src/script.rs @@ -226,11 +226,9 @@ impl ScriptTester { trace!(target: "tests", "STDOUT\n{stdout}\n\nSTDERR\n{stderr}"); - let output = if expected.is_err() { &stderr } else { &stdout }; - if !output.contains(expected.as_str()) { - let which = if expected.is_err() { "stderr" } else { "stdout" }; + if !stdout.contains(expected.as_str()) && !stderr.contains(expected.as_str()) { panic!( - "--STDOUT--\n{stdout}\n\n--STDERR--\n{stderr}\n\n--EXPECTED--\n{:?} in {which}", + "--STDOUT--\n{stdout}\n\n--STDERR--\n{stderr}\n\n--EXPECTED--\n{:?} not found in stdout or stderr", expected.as_str() ); } @@ -286,7 +284,7 @@ impl ScriptOutcome { Self::OkNoEndpoint => "If you wish to simulate on-chain transactions pass a RPC URL.", Self::OkSimulation => "SIMULATION COMPLETE. To broadcast these", Self::OkBroadcast => "ONCHAIN EXECUTION COMPLETE & SUCCESSFUL", - Self::WarnSpecifyDeployer => "You have more than one deployer who could predeploy libraries. Using `--sender` instead.", + Self::WarnSpecifyDeployer => "Warning: You have more than one deployer who could predeploy libraries. Using `--sender` instead.", Self::MissingSender => "You seem to be using Foundry's default sender. Be sure to set your own --sender", Self::MissingWallet => "No associated wallet", Self::StaticCallNotAllowed => "staticcall`s are not allowed after `broadcast`; use `startBroadcast` instead", diff --git a/crates/verify/src/bytecode.rs b/crates/verify/src/bytecode.rs index 661eb5c8d..a4f368a96 100644 --- a/crates/verify/src/bytecode.rs +++ b/crates/verify/src/bytecode.rs @@ -16,6 +16,7 @@ use foundry_cli::{ opts::EtherscanOpts, utils::{self, read_constructor_args_file, LoadConfig}, }; +use foundry_common::shell; use foundry_compilers::{artifacts::EvmVersion, info::ContractInfo}; use foundry_config::{figment, impl_figment_convert, Config}; use foundry_evm::{constants::DEFAULT_CREATE2_DEPLOYER, utils::configure_tx_env}; @@ -75,10 +76,6 @@ pub struct VerifyBytecodeArgs { #[clap(flatten)] pub verifier: VerifierArgs, - /// Suppress logs and emit json results to stdout - #[clap(long, default_value = "false")] - pub json: bool, - /// The project's root path. /// /// By default root of the Git repository, if in one, @@ -144,7 +141,7 @@ impl VerifyBytecodeArgs { eyre::bail!("No bytecode found at address {}", self.address); } - if !self.json { + if !shell::is_json() { println!( "Verifying bytecode for contract {} at address {}", self.contract.name.clone().green(), @@ -214,7 +211,7 @@ impl VerifyBytecodeArgs { crate::utils::check_args_len(&artifact, &constructor_args)?; if maybe_predeploy { - if !self.json { + if !shell::is_json() { println!( "{}", format!("Attempting to verify predeployed contract at {:?}. Ignoring creation code verification.", self.address) @@ -290,7 +287,6 @@ impl VerifyBytecodeArgs { ); crate::utils::print_result( - &self, match_type, BytecodeType::Runtime, &mut json_results, @@ -298,8 +294,8 @@ impl VerifyBytecodeArgs { &config, ); - if self.json { - println!("{}", serde_json::to_string(&json_results)?); + if shell::is_json() { + sh_println!("{}", serde_json::to_string(&json_results)?)?; } return Ok(()); @@ -376,7 +372,6 @@ impl VerifyBytecodeArgs { ); crate::utils::print_result( - &self, match_type, BytecodeType::Creation, &mut json_results, @@ -387,15 +382,14 @@ impl VerifyBytecodeArgs { // If the creation code does not match, the runtime also won't match. Hence return. if match_type.is_none() { crate::utils::print_result( - &self, None, BytecodeType::Runtime, &mut json_results, etherscan_metadata, &config, ); - if self.json { - println!("{}", serde_json::to_string(&json_results)?); + if shell::is_json() { + sh_println!("{}", serde_json::to_string(&json_results)?)?; } return Ok(()); } @@ -488,7 +482,6 @@ impl VerifyBytecodeArgs { ); crate::utils::print_result( - &self, match_type, BytecodeType::Runtime, &mut json_results, @@ -497,8 +490,8 @@ impl VerifyBytecodeArgs { ); } - if self.json { - println!("{}", serde_json::to_string(&json_results)?); + if shell::is_json() { + sh_println!("{}", serde_json::to_string(&json_results)?)?; } Ok(()) } diff --git a/crates/verify/src/etherscan/mod.rs b/crates/verify/src/etherscan/mod.rs index 2f29a6c67..2517d106d 100644 --- a/crates/verify/src/etherscan/mod.rs +++ b/crates/verify/src/etherscan/mod.rs @@ -18,7 +18,6 @@ use foundry_cli::utils::{get_provider, read_constructor_args_file, LoadConfig}; use foundry_common::{ abi::encode_function_args, retry::{Retry, RetryError}, - shell, }; use foundry_compilers::{artifacts::BytecodeObject, Artifact}; use foundry_config::{Chain, Config}; @@ -466,9 +465,7 @@ impl EtherscanVerificationProvider { if maybe_creation_code.starts_with(bytecode) { let constructor_args = &maybe_creation_code[bytecode.len()..]; let constructor_args = hex::encode(constructor_args); - shell::println(format!( - "Identified constructor arguments: {constructor_args}" - ))?; + sh_println!("Identified constructor arguments: {constructor_args}")?; Ok(constructor_args) } else { eyre::bail!("Local bytecode doesn't match on-chain bytecode") @@ -493,9 +490,7 @@ impl EtherscanVerificationProvider { if maybe_creation_code.starts_with(bytecode) { let constructor_args = &maybe_creation_code[bytecode.len()..]; let constructor_args = hex::encode(constructor_args); - shell::println(format!( - "Identified constructor arguments: {constructor_args}" - ))?; + sh_println!("Identified constructor arguments: {constructor_args}")?; Ok(constructor_args) } else { eyre::bail!("Local bytecode doesn't match on-chain bytecode") @@ -642,6 +637,7 @@ mod tests { cmd.args(["build", "--force"]).assert_success().stdout_eq(str![[r#" [COMPILING_FILES] with [SOLC_VERSION] +... [SOLC_VERSION] [ELAPSED] Compiler run successful! diff --git a/crates/verify/src/lib.rs b/crates/verify/src/lib.rs index 5a3431cf1..12145d19b 100644 --- a/crates/verify/src/lib.rs +++ b/crates/verify/src/lib.rs @@ -3,6 +3,12 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#[macro_use] +extern crate foundry_common; + +#[macro_use] +extern crate tracing; + mod etherscan; pub mod provider; @@ -22,6 +28,3 @@ pub use verify::{VerifierArgs, VerifyArgs, VerifyCheckArgs}; mod types; mod utils; - -#[macro_use] -extern crate tracing; diff --git a/crates/verify/src/utils.rs b/crates/verify/src/utils.rs index aaf8a0e01..e3065aca0 100644 --- a/crates/verify/src/utils.rs +++ b/crates/verify/src/utils.rs @@ -9,7 +9,7 @@ use foundry_block_explorers::{ contract::{ContractCreationData, ContractMetadata, Metadata}, errors::EtherscanError, }; -use foundry_common::{abi::encode_args, compile::ProjectCompiler, provider::RetryProvider}; +use foundry_common::{abi::encode_args, compile::ProjectCompiler, provider::RetryProvider, shell}; use foundry_compilers::artifacts::{BytecodeHash, CompactContractBytecode, EvmVersion}; use foundry_config::Config; use foundry_evm::{constants::DEFAULT_CREATE2_DEPLOYER, executors::TracingExecutor, opts::EvmOpts}; @@ -137,7 +137,6 @@ pub fn build_using_cache( } pub fn print_result( - args: &VerifyBytecodeArgs, res: Option, bytecode_type: BytecodeType, json_results: &mut Vec, @@ -145,7 +144,7 @@ pub fn print_result( config: &Config, ) { if let Some(res) = res { - if !args.json { + if !shell::is_json() { println!( "{} with status {}", format!("{bytecode_type:?} code matched").green().bold(), @@ -155,7 +154,7 @@ pub fn print_result( let json_res = JsonResult { bytecode_type, match_type: Some(res), message: None }; json_results.push(json_res); } - } else if !args.json { + } else if !shell::is_json() { println!( "{}", format!( diff --git a/crates/zksync/core/src/convert/eip712.rs b/crates/zksync/core/src/convert/eip712.rs index 8a95f18e3..228d598fd 100644 --- a/crates/zksync/core/src/convert/eip712.rs +++ b/crates/zksync/core/src/convert/eip712.rs @@ -56,39 +56,50 @@ impl ConvertEIP712Domain for EthersEip712Domain { } /// Wrapper around [`Eip712Transaction`] implementing [`SignableTransaction`] -pub struct Eip712SignableTransaction(Eip712Transaction); +#[derive(Debug)] +pub struct Eip712SignableTransaction { + inner: Eip712Transaction, + input: alloy_primitives::Bytes, +} + +impl Eip712SignableTransaction { + /// Creates a new `Eip712SignableTransaction` from an existing `Eip712Transaction`. + pub fn new(inner: Eip712Transaction) -> Self { + Self { input: alloy_primitives::Bytes::from_iter(inner.data.iter()), inner } + } +} impl Transaction for Eip712SignableTransaction { fn chain_id(&self) -> Option { - Some(self.0.chain_id.as_u64()) + Some(self.inner.chain_id.as_u64()) } fn nonce(&self) -> u64 { - self.0.nonce.as_u64() + self.inner.nonce.as_u64() } fn gas_limit(&self) -> u64 { - self.0.gas_limit.as_u64() + self.inner.gas_limit.as_u64() } fn gas_price(&self) -> Option { None } - fn to(&self) -> alloy_primitives::TxKind { - alloy_primitives::TxKind::Call(self.0.to.to_address()) + fn to(&self) -> Option { + Some(self.inner.to.to_address()) } fn value(&self) -> alloy_primitives::U256 { - self.0.value.to_ru256() + self.inner.value.to_ru256() } - fn input(&self) -> &[u8] { - self.0.data.as_ref() + fn input(&self) -> &alloy_primitives::Bytes { + &self.input } fn max_fee_per_gas(&self) -> u128 { - self.0.max_fee_per_gas.low_u128() + self.inner.max_fee_per_gas.low_u128() } fn max_priority_fee_per_gas(&self) -> Option { @@ -100,7 +111,7 @@ impl Transaction for Eip712SignableTransaction { } fn priority_fee_or_price(&self) -> u128 { - self.0.max_priority_fee_per_gas.low_u128() + self.inner.max_priority_fee_per_gas.low_u128() } fn ty(&self) -> u8 { @@ -118,21 +129,25 @@ impl Transaction for Eip712SignableTransaction { fn authorization_list(&self) -> Option<&[revm::primitives::SignedAuthorization]> { None } + + fn kind(&self) -> alloy_primitives::TxKind { + alloy_primitives::TxKind::Call(self.inner.to.to_address()) + } } impl SignableTransaction for Eip712SignableTransaction { fn set_chain_id(&mut self, chain_id: alloy_primitives::ChainId) { - self.0.chain_id = chain_id.into(); + self.inner.chain_id = chain_id.into(); } fn encode_for_signing(&self, out: &mut dyn BufMut) { out.put_u8(0x19); out.put_u8(0x01); - let domain_separator = self.0.domain_separator().expect("able to get domain separator"); + let domain_separator = self.inner.domain_separator().expect("able to get domain separator"); out.put_slice(&domain_separator); - let struct_hash = self.0.struct_hash().expect("able to get struct hash"); + let struct_hash = self.inner.struct_hash().expect("able to get struct hash"); out.put_slice(&struct_hash); } @@ -144,7 +159,7 @@ impl SignableTransaction for Eip712SignableTransaction { where Self: Sized, { - let hash = self.0.encode_eip712().map(B256::from).expect("able to encode EIP712 hash"); + let hash = self.inner.encode_eip712().map(B256::from).expect("able to encode EIP712 hash"); alloy_consensus::Signed::new_unchecked(self, signature, hash) } } @@ -162,7 +177,7 @@ impl ToSignable for Eip712Transaction { type Signable = Eip712SignableTransaction; fn to_signable_tx(self) -> Self::Signable { - Eip712SignableTransaction(self) + Eip712SignableTransaction::new(self) } } diff --git a/crates/zksync/core/src/vm/inspect.rs b/crates/zksync/core/src/vm/inspect.rs index 801c686a4..5742fba60 100644 --- a/crates/zksync/core/src/vm/inspect.rs +++ b/crates/zksync/core/src/vm/inspect.rs @@ -19,8 +19,8 @@ use tracing::{debug, error, info, trace, warn}; use zksync_basic_types::{ethabi, L2ChainId, Nonce, H160, H256, U256}; use zksync_multivm::{ interface::{ - Call, CallType, ExecutionResult, Halt, VmEvent, VmExecutionMode, VmExecutionResultAndLogs, - VmFactory, VmInterface, VmRevertReason, + Call, CallType, ExecutionResult, Halt, InspectExecutionMode, VmEvent, + VmExecutionResultAndLogs, VmFactory, VmInterface, VmRevertReason, }, tracers::CallTracer, vm_latest::{HistoryDisabled, ToTracerPointer, Vm}, @@ -455,7 +455,7 @@ fn inspect_inner( .into_tracer_pointer(), ]; let compressed_bytecodes = vm.push_transaction(tx).compressed_bytecodes.into_owned(); - let mut tx_result = vm.inspect(&mut tracers.into(), VmExecutionMode::OneTx); + let mut tx_result = vm.inspect(&mut tracers.into(), InspectExecutionMode::OneTx); let mut call_traces = Arc::try_unwrap(call_tracer_result).unwrap().take().unwrap_or_default(); trace!(?tx_result.result, "zk vm result"); diff --git a/testdata/cheats/Vm.sol b/testdata/cheats/Vm.sol index 7c2943a1d..2f6ba7dac 100644 --- a/testdata/cheats/Vm.sol +++ b/testdata/cheats/Vm.sol @@ -9,6 +9,7 @@ interface Vm { enum CallerMode { None, Broadcast, RecurrentBroadcast, Prank, RecurrentPrank } enum AccountAccessKind { Call, DelegateCall, CallCode, StaticCall, Create, SelfDestruct, Resume, Balance, Extcodesize, Extcodehash, Extcodecopy } enum ForgeContext { TestGroup, Test, Coverage, Snapshot, ScriptGroup, ScriptDryRun, ScriptBroadcast, ScriptResume, Unknown } + enum BroadcastTxType { Call, Create, Create2 } struct Log { bytes32[] topics; bytes data; address emitter; } struct Rpc { string key; string url; } struct EthGetLogs { address emitter; bytes32[] topics; bytes data; bytes32 blockHash; uint64 blockNumber; bytes32 transactionHash; uint64 transactionIndex; uint256 logIndex; bool removed; } @@ -21,6 +22,7 @@ interface Vm { struct StorageAccess { address account; bytes32 slot; bool isWrite; bytes32 previousValue; bytes32 newValue; bool reverted; } struct Gas { uint64 gasLimit; uint64 gasTotalUsed; uint64 gasMemoryUsed; int64 gasRefunded; uint64 gasRemaining; } struct DebugStep { uint256[] stack; bytes memoryInput; uint8 opcode; uint64 depth; bool isOutOfGas; address contractAddr; } + struct BroadcastTxSummary { bytes32 txHash; BroadcastTxType txType; address contractAddress; uint64 blockNumber; bool success; } function _expectCheatcodeRevert() external; function _expectCheatcodeRevert(bytes4 revertData) external; function _expectCheatcodeRevert(bytes calldata revertData) external; @@ -336,8 +338,14 @@ interface Vm { function getBlobhashes() external view returns (bytes32[] memory hashes); function getBlockNumber() external view returns (uint256 height); function getBlockTimestamp() external view returns (uint256 timestamp); + function getBroadcast(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary memory); + function getBroadcasts(string memory contractName, uint64 chainId, BroadcastTxType txType) external returns (BroadcastTxSummary[] memory); + function getBroadcasts(string memory contractName, uint64 chainId) external returns (BroadcastTxSummary[] memory); function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode); function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); + function getDeployment(string memory contractName) external returns (address deployedAddress); + function getDeployment(string memory contractName, uint64 chainId) external returns (address deployedAddress); + function getDeployments(string memory contractName, uint64 chainId) external returns (address[] memory deployedAddresses); function getFoundryVersion() external view returns (string memory version); function getLabel(address account) external view returns (string memory currentLabel); function getMappingKeyAndParentOf(address target, bytes32 elementSlot) diff --git a/testdata/default/cheats/Fork2.t.sol b/testdata/default/cheats/Fork2.t.sol index 7b6b42759..d0703ce7f 100644 --- a/testdata/default/cheats/Fork2.t.sol +++ b/testdata/default/cheats/Fork2.t.sol @@ -234,6 +234,12 @@ contract ForkTest is DSTest { uint256 decodedResult = vm.parseUint(vm.toString(result)); assertGt(decodedResult, 20_000_000); } + + // + function testRpcTransactionByHash() public { + string memory param = string.concat('["0xe1a0fba63292976050b2fbf4379a1901691355ed138784b4e0d1854b4cf9193e"]'); + vm.rpc("sepolia", "eth_getTransactionByHash", param); + } } contract DummyContract { diff --git a/testdata/forge-std-rev b/testdata/forge-std-rev index c6c6e2da6..ff90d09c2 100644 --- a/testdata/forge-std-rev +++ b/testdata/forge-std-rev @@ -1 +1 @@ -8f24d6b04c92975e0795b5868aa0d783251cdeaa \ No newline at end of file +1eea5bae12ae557d589f9f0f0edae2faa47cb262 \ No newline at end of file