diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9c5e69fb57f80..89d93d9cdfeef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ env: CARGO_TERM_COLOR: always IS_NIGHTLY: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} PROFILE: maxperf - STABLE_VERSION: "v1.3.6" + STABLE_VERSION: "v1.4.3" jobs: prepare: diff --git a/Cargo.lock b/Cargo.lock index e028beab93def..7248dbf76a581 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1070,7 +1070,7 @@ dependencies = [ [[package]] name = "anvil" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-chains", "alloy-consensus", @@ -1136,7 +1136,7 @@ dependencies = [ [[package]] name = "anvil-core" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -1161,7 +1161,7 @@ dependencies = [ [[package]] name = "anvil-rpc" -version = "1.4.3" +version = "1.4.4" dependencies = [ "serde", "serde_json", @@ -1169,7 +1169,7 @@ dependencies = [ [[package]] name = "anvil-server" -version = "1.4.3" +version = "1.4.4" dependencies = [ "anvil-rpc", "async-trait", @@ -2538,7 +2538,7 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cast" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-chains", "alloy-consensus", @@ -2642,7 +2642,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chisel" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4036,7 +4036,7 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "forge" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-chains", "alloy-dyn-abi", @@ -4117,7 +4117,7 @@ dependencies = [ [[package]] name = "forge-doc" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-primitives", "derive_more", @@ -4141,7 +4141,7 @@ dependencies = [ [[package]] name = "forge-fmt" -version = "1.4.3" +version = "1.4.4" dependencies = [ "foundry-common", "foundry-config", @@ -4157,7 +4157,7 @@ dependencies = [ [[package]] name = "forge-lint" -version = "1.4.3" +version = "1.4.4" dependencies = [ "eyre", "foundry-common", @@ -4171,7 +4171,7 @@ dependencies = [ [[package]] name = "forge-script" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-chains", "alloy-consensus", @@ -4215,7 +4215,7 @@ dependencies = [ [[package]] name = "forge-script-sequence" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-network", "alloy-primitives", @@ -4231,7 +4231,7 @@ dependencies = [ [[package]] name = "forge-sol-macro-gen" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -4246,7 +4246,7 @@ dependencies = [ [[package]] name = "forge-verify" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4326,7 +4326,7 @@ dependencies = [ [[package]] name = "foundry-cheatcodes" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-chains", "alloy-consensus", @@ -4377,7 +4377,7 @@ dependencies = [ [[package]] name = "foundry-cheatcodes-spec" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-sol-types", "foundry-macros", @@ -4388,7 +4388,7 @@ dependencies = [ [[package]] name = "foundry-cli" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-chains", "alloy-dyn-abi", @@ -4436,7 +4436,7 @@ dependencies = [ [[package]] name = "foundry-common" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-chains", "alloy-consensus", @@ -4492,7 +4492,7 @@ dependencies = [ [[package]] name = "foundry-common-fmt" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -4613,7 +4613,7 @@ dependencies = [ [[package]] name = "foundry-config" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-chains", "alloy-primitives", @@ -4653,7 +4653,7 @@ dependencies = [ [[package]] name = "foundry-debugger" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-primitives", "crossterm 0.29.0", @@ -4671,7 +4671,7 @@ dependencies = [ [[package]] name = "foundry-evm" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-dyn-abi", "alloy-evm", @@ -4703,7 +4703,7 @@ dependencies = [ [[package]] name = "foundry-evm-abi" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -4715,7 +4715,7 @@ dependencies = [ [[package]] name = "foundry-evm-core" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-chains", "alloy-consensus", @@ -4755,7 +4755,7 @@ dependencies = [ [[package]] name = "foundry-evm-coverage" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-primitives", "eyre", @@ -4771,7 +4771,7 @@ dependencies = [ [[package]] name = "foundry-evm-fuzz" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4795,7 +4795,7 @@ dependencies = [ [[package]] name = "foundry-evm-networks" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-chains", "alloy-evm", @@ -4807,7 +4807,7 @@ dependencies = [ [[package]] name = "foundry-evm-traces" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -4861,7 +4861,7 @@ dependencies = [ [[package]] name = "foundry-linking" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-primitives", "foundry-compilers", @@ -4872,7 +4872,7 @@ dependencies = [ [[package]] name = "foundry-macros" -version = "1.4.3" +version = "1.4.4" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -4896,7 +4896,7 @@ dependencies = [ [[package]] name = "foundry-test-utils" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-primitives", "alloy-provider", @@ -4923,7 +4923,7 @@ dependencies = [ [[package]] name = "foundry-wallets" -version = "1.4.3" +version = "1.4.4" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -9141,8 +9141,7 @@ dependencies = [ [[package]] name = "solar-ast" version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6aaf98d032ba3be85dca5f969895ade113a9137bb5956f80c5faf14689de59" +source = "git+https://github.com/paradigmxyz/solar.git?rev=0bea5f0#0bea5f09ac7a3895cac27e111b429a4c30968168" dependencies = [ "alloy-primitives", "bumpalo", @@ -9158,8 +9157,7 @@ dependencies = [ [[package]] name = "solar-compiler" version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95e792060bcbb007a6b9b060292945fb34ff854c7d93a9628f81b6c809eb4360" +source = "git+https://github.com/paradigmxyz/solar.git?rev=0bea5f0#0bea5f09ac7a3895cac27e111b429a4c30968168" dependencies = [ "alloy-primitives", "solar-ast", @@ -9174,8 +9172,7 @@ dependencies = [ [[package]] name = "solar-config" version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff16d692734c757edd339f5db142ba91b42772f8cbe1db1ce3c747f1e777185f" +source = "git+https://github.com/paradigmxyz/solar.git?rev=0bea5f0#0bea5f09ac7a3895cac27e111b429a4c30968168" dependencies = [ "colorchoice", "strum 0.27.2", @@ -9184,8 +9181,7 @@ dependencies = [ [[package]] name = "solar-data-structures" version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dea34e58332c7d6a8cde1f1740186d31682b7be46e098b8cc16fcb7ffd98bf5" +source = "git+https://github.com/paradigmxyz/solar.git?rev=0bea5f0#0bea5f09ac7a3895cac27e111b429a4c30968168" dependencies = [ "bumpalo", "index_vec", @@ -9199,8 +9195,7 @@ dependencies = [ [[package]] name = "solar-interface" version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6163af2e773f4d455212fa9ba2c0664506029dd26232eb406f5046092ac311" +source = "git+https://github.com/paradigmxyz/solar.git?rev=0bea5f0#0bea5f09ac7a3895cac27e111b429a4c30968168" dependencies = [ "annotate-snippets 0.12.4", "anstream", @@ -9208,7 +9203,7 @@ dependencies = [ "derive_more", "dunce", "inturn", - "itertools 0.14.0", + "itertools 0.10.5", "itoa", "normalize-path", "once_map", @@ -9227,8 +9222,7 @@ dependencies = [ [[package]] name = "solar-macros" version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44a98045888d75d17f52e7b76f6098844b76078b5742a450c3ebcdbdb02da124" +source = "git+https://github.com/paradigmxyz/solar.git?rev=0bea5f0#0bea5f09ac7a3895cac27e111b429a4c30968168" dependencies = [ "proc-macro2", "quote", @@ -9238,13 +9232,12 @@ dependencies = [ [[package]] name = "solar-parse" version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b77a9cbb07948e4586cdcf64f0a483424197308816ebd57a4cf06130b68562" +source = "git+https://github.com/paradigmxyz/solar.git?rev=0bea5f0#0bea5f09ac7a3895cac27e111b429a4c30968168" dependencies = [ "alloy-primitives", "bitflags 2.9.4", "bumpalo", - "itertools 0.14.0", + "itertools 0.10.5", "memchr", "num-bigint", "num-rational", @@ -9260,8 +9253,7 @@ dependencies = [ [[package]] name = "solar-sema" version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd033af43a38da316a04b25bbd20b121ce5d728b61e6988fd8fd6e2f1e68d0a1" +source = "git+https://github.com/paradigmxyz/solar.git?rev=0bea5f0#0bea5f09ac7a3895cac27e111b429a4c30968168" dependencies = [ "alloy-json-abi", "alloy-primitives", diff --git a/Cargo.toml b/Cargo.toml index 4eddaf4409610..a34d49682a7b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ members = [ resolver = "2" [workspace.package] -version = "1.4.3" +version = "1.4.4" edition = "2024" # Remember to update clippy.toml as well rust-version = "1.89" @@ -431,7 +431,7 @@ rexpect = { git = "https://github.com/rust-cli/rexpect", rev = "2ed0b1898d7edaf6 # foundry-fork-db = { git = "https://github.com/foundry-rs/foundry-fork-db", rev = "eee6563" } # solar -# solar = { package = "solar-compiler", git = "https://github.com/paradigmxyz/solar.git", branch = "main" } -# solar-interface = { package = "solar-interface", git = "https://github.com/paradigmxyz/solar.git", branch = "main" } -# solar-ast = { package = "solar-ast", git = "https://github.com/paradigmxyz/solar.git", branch = "main" } -# solar-sema = { package = "solar-sema", git = "https://github.com/paradigmxyz/solar.git", branch = "main" } +solar = { package = "solar-compiler", git = "https://github.com/paradigmxyz/solar.git", rev = "0bea5f0" } +solar-interface = { package = "solar-interface", git = "https://github.com/paradigmxyz/solar.git", rev = "0bea5f0" } +solar-ast = { package = "solar-ast", git = "https://github.com/paradigmxyz/solar.git", rev = "0bea5f0" } +solar-sema = { package = "solar-sema", git = "https://github.com/paradigmxyz/solar.git", rev = "0bea5f0" } diff --git a/crates/anvil/tests/it/fork.rs b/crates/anvil/tests/it/fork.rs index 538a4256e795e..409e212db7479 100644 --- a/crates/anvil/tests/it/fork.rs +++ b/crates/anvil/tests/it/fork.rs @@ -1221,7 +1221,7 @@ 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_block_number = 394274860u64; let fork_rpc = next_rpc_endpoint(NamedChain::Arbitrum); let (api, _handle) = spawn( fork_config() diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index d9c8d9b65a490..4ee68d9d14bcb 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -3386,7 +3386,7 @@ Traces: │ ├─ [2553] 0x2Ce6311ddAE708829bc0784C967b7d77D19FD779::balanceOf(0xA12384c5E52fD646E7BC7F6B3b33A605651F566E) [delegatecall] │ │ └─ ← [Return] 0x000000000000000000000000000000000000000000000000000000000000f3b9 │ └─ ← [Return] 0x000000000000000000000000000000000000000000000000000000000000f3b9 - ├─ [65442] 0xc2FF493F28e894742b968A7DB5D3F21F0aD80C6c::00000000(00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a12384c5e52fd646e7bc7f6b3b33a605651f566e000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000036cd000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000327a25ad5cfe5c4d4339c1a4267d4a83e8c93312000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000b55b053230e4effb6609de652fca73fd1c2980400000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000221000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) + ├─ [65442] 0xc2FF493F28e894742b968A7DB5D3F21F0aD80C6c::fulfillBasicOrder_efficient_6GL6yc() │ ├─ [25070] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::unwrapAndValidateSignature(0x290a4c4039f102eceba2147e1fcc46f994a46d1229faf43ffff26a058e7378ff, 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b00) [staticcall] │ │ ├─ [22067] 0x0B55b053230E4EFFb6609de652fCa73Fd1C29804::unwrapAndValidateSignature(0x290a4c4039f102eceba2147e1fcc46f994a46d1229faf43ffff26a058e7378ff, 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b00) [delegatecall] │ │ │ ├─ [2369] 0xc2FF493F28e894742b968A7DB5D3F21F0aD80C6c::pauseFlag() [staticcall] @@ -3420,7 +3420,7 @@ Traces: │ │ ├─ [553] 0x2Ce6311ddAE708829bc0784C967b7d77D19FD779::balanceOf(0x327a25aD5Cfe5c4D4339C1A4267D4a83E8c93312) [delegatecall] │ │ │ └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000009c9a │ │ └─ ← [Return] 0x0000000000000000000000000000000000000000000000000000000000009c9a - │ ├─ [5675] 0xc2FF493F28e894742b968A7DB5D3F21F0aD80C6c::00000001(00000000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b290a4c4039f102eceba2147e1fcc46f994a46d1229faf43ffff26a058e7378ff0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000a12384c5e52fd646e7bc7f6b3b33a605651f566e000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000036cd000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000327a25ad5cfe5c4d4339c1a4267d4a83e8c93312000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000005a00000000000000000000000000b55b053230e4effb6609de652fca73fd1c2980400000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000221000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006cdd519280ec730727f07aa36550bde31a1d5f3097818f3425c2f083ed33a91f080fa2afac0071f6e1af9a0e9c09b851bf01e68bc8a1c1f89f686c48205762f92500000000000000000000000000000000000000000000000000000000000000244242424242424242424242424242424242424242424242424242424242424242010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000827b226368616c6c656e6765223a224b51704d51446e7841757a726f68522d483878472d5a536b625249702d76515f5f5f4a714259357a655038222c2263726f73734f726967696e223a66616c73652c226f726967696e223a2268747470732f2f6974686163612e78797a222c2274797065223a22776562617574686e2e676574227d0000000000000000000000000000000000000000000000000000000000001bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) + │ ├─ [5675] 0xc2FF493F28e894742b968A7DB5D3F21F0aD80C6c::multicallN2M_001Taw5z() │ │ ├─ [4148] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::execute(0x0100000000007821000100000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000201bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b) │ │ │ ├─ [3693] 0x0B55b053230E4EFFb6609de652fCa73Fd1C29804::execute(0x0100000000007821000100000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000201bde17b8de18819c9eb86cefc3920ddb5d3d4254de276e3d6e18dd2b399f732b) [delegatecall] │ │ │ │ ├─ [435] 0xA12384c5E52fD646E7BC7F6B3b33A605651F566E::fallback() diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index dd4e8301366e6..49736b8bcf166 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -498,11 +498,8 @@ pub struct Cheatcodes { pub wallets: Option, /// Signatures identifier for decoding events and functions signatures_identifier: OnceLock>, - /// Used to determine whether the broadcasted call has non-fixed gas limit. - /// Holds values for (seen opcode GAS, seen opcode CALL) pair. - /// If GAS opcode is followed by CALL opcode then both flags are marked true and call - /// has non-fixed gas limit, otherwise the call is considered to have fixed gas limit. - pub dynamic_gas_limit_sequence: Option<(bool, bool)>, + /// Used to determine whether the broadcasted call has dynamic gas limit. + pub dynamic_gas_limit: bool, } // This is not derived because calling this in `fn new` with `..Default::default()` creates a second @@ -558,7 +555,7 @@ impl Cheatcodes { deprecated: Default::default(), wallets: Default::default(), signatures_identifier: Default::default(), - dynamic_gas_limit_sequence: Default::default(), + dynamic_gas_limit: Default::default(), } } @@ -835,6 +832,11 @@ impl Cheatcodes { // Apply our broadcast if let Some(broadcast) = &self.broadcast { + // Additional check as transfers in forge scripts seem to be estimated at 2300 + // by revm leading to "Intrinsic gas too low" failure when simulated on chain. + let is_fixed_gas_limit = call.gas_limit >= 21_000 && !self.dynamic_gas_limit; + self.dynamic_gas_limit = false; + // We only apply a broadcast *to a specific depth*. // // We do this because any subsequent contract calls *must* exist on chain and @@ -862,15 +864,6 @@ impl Cheatcodes { }); } - let (gas_seen, call_seen) = - self.dynamic_gas_limit_sequence.take().unwrap_or_default(); - // Transaction has fixed gas limit if no GAS opcode seen before CALL opcode. - let mut is_fixed_gas_limit = !(gas_seen && call_seen); - // Additional check as transfers in forge scripts seem to be estimated at 2300 - // by revm leading to "Intrinsic gas too low" failure when simulated on chain. - if call.gas_limit < 21_000 { - is_fixed_gas_limit = false; - } let input = TransactionInput::new(call.input.bytes(ecx)); // Ensure account is touched. ecx.journaled_state.touch(broadcast.new_origin); @@ -1095,7 +1088,7 @@ impl Inspector> for Cheatcodes { self.pc = interpreter.bytecode.pc(); if self.broadcast.is_some() { - self.record_gas_limit_opcode(interpreter); + self.set_gas_limit_type(interpreter); } // `pauseGasMetering`: pause / resume interpreter gas. @@ -1138,10 +1131,6 @@ impl Inspector> for Cheatcodes { } fn step_end(&mut self, interpreter: &mut Interpreter, ecx: Ecx) { - if self.broadcast.is_some() { - self.set_gas_limit_type(interpreter); - } - if self.gas_metering.paused { self.meter_gas_end(interpreter); } @@ -2331,38 +2320,18 @@ impl Cheatcodes { } #[cold] - fn record_gas_limit_opcode(&mut self, interpreter: &mut Interpreter) { + fn set_gas_limit_type(&mut self, interpreter: &mut Interpreter) { match interpreter.bytecode.opcode() { - // If current opcode is CREATE2 then set non-fixed gas limit. - op::CREATE2 => self.dynamic_gas_limit_sequence = Some((true, true)), - op::GAS => { - if self.dynamic_gas_limit_sequence.is_none() { - // If current opcode is GAS then mark as seen. - self.dynamic_gas_limit_sequence = Some((true, false)); - } + op::CREATE2 => self.dynamic_gas_limit = true, + op::CALL => { + // If first element of the stack is close to current remaining gas then assume + // dynamic gas limit. + self.dynamic_gas_limit = + try_or_return!(interpreter.stack.peek(0)) >= interpreter.gas.remaining() - 100 } - _ => {} + _ => self.dynamic_gas_limit = false, } } - - #[cold] - fn set_gas_limit_type(&mut self, interpreter: &mut Interpreter) { - // Early exit in case we already determined is non-fixed gas limit. - if matches!(self.dynamic_gas_limit_sequence, Some((true, true))) { - return; - } - - // Record CALL opcode if GAS opcode was seen. - if matches!(self.dynamic_gas_limit_sequence, Some((true, false))) - && interpreter.bytecode.opcode() == op::CALL - { - self.dynamic_gas_limit_sequence = Some((true, true)); - return; - } - - // Reset dynamic gas limit sequence if GAS opcode was not followed by a CALL opcode. - self.dynamic_gas_limit_sequence = None; - } } /// Helper that expands memory, stores a revert string pertaining to a disallowed memory write, diff --git a/crates/config/src/fmt.rs b/crates/config/src/fmt.rs index 415be41f1f2f3..73b59dc6418c7 100644 --- a/crates/config/src/fmt.rs +++ b/crates/config/src/fmt.rs @@ -29,6 +29,8 @@ pub struct FormatterConfig { pub override_spacing: bool, /// Wrap comments on `line_length` reached pub wrap_comments: bool, + /// Style of doc comments + pub docs_style: DocCommentStyle, /// Globs to ignore pub ignore: Vec, /// Add new line at start and end of contract declarations @@ -37,8 +39,11 @@ pub struct FormatterConfig { pub sort_imports: bool, /// Whether to suppress spaces around the power operator (`**`). pub pow_no_space: bool, - /// Whether to compact call args in a single line when possible - pub call_compact_args: bool, + /// Style that determines if a broken list, should keep its elements together on their own + /// line, before breaking individually. + pub prefer_compact: PreferCompact, + /// Keep single imports on a single line even if they exceed line length. + pub single_line_imports: bool, } /// Style of integer types. @@ -101,6 +106,19 @@ pub enum HexUnderscore { Bytes, } +/// Style of doc comments +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum DocCommentStyle { + /// Preserve the source code style + #[default] + Preserve, + /// Use single-line style (`///`) + Line, + /// Use block style (`/** .. */`) + Block, +} + /// Style of string quotes #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] @@ -170,6 +188,40 @@ impl MultilineFuncHeaderStyle { } } +/// Style that determines if a broken list, should keep its elements together on their own line, +/// before breaking individually. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum PreferCompact { + /// All elements are preferred consistent. + None, + /// Calls are preferred compact. Events and errors break consistently. + Calls, + /// Events are preferred compact. Calls and errors break consistently. + Events, + /// Errors are preferred compact. Calls and events break consistently. + Errors, + /// Events and errors are preferred compact. Calls break consistently. + EventsErrors, + /// All elements are preferred compact. + #[default] + All, +} + +impl PreferCompact { + pub fn calls(&self) -> bool { + matches!(self, Self::All | Self::Calls) + } + + pub fn events(&self) -> bool { + matches!(self, Self::All | Self::Events | Self::EventsErrors) + } + + pub fn errors(&self) -> bool { + matches!(self, Self::All | Self::Errors | Self::EventsErrors) + } +} + /// Style of indent #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] @@ -198,7 +250,9 @@ impl Default for FormatterConfig { contract_new_lines: false, sort_imports: false, pow_no_space: false, - call_compact_args: true, + prefer_compact: PreferCompact::default(), + docs_style: DocCommentStyle::default(), + single_line_imports: false, } } } diff --git a/crates/evm/evm/src/executors/fuzz/mod.rs b/crates/evm/evm/src/executors/fuzz/mod.rs index cc90e0670fae6..e9623855d6473 100644 --- a/crates/evm/evm/src/executors/fuzz/mod.rs +++ b/crates/evm/evm/src/executors/fuzz/mod.rs @@ -227,12 +227,19 @@ impl FuzzedExecutor { // Discard run and apply max rejects if configured. Saturate to handle // the case of replayed failure, which doesn't count as a run. test_data.runs = test_data.runs.saturating_sub(1); - if self.config.max_test_rejects > 0 { - test_data.rejects += 1; - if test_data.rejects >= self.config.max_test_rejects { - test_data.failure = Some(err); - break 'stop; - } + test_data.rejects += 1; + + // Update progress bar to reflect rejected runs. + if let Some(progress) = progress { + progress.set_message(format!("([{}] rejected)", test_data.rejects)); + progress.dec(1); + } + + if self.config.max_test_rejects > 0 + && test_data.rejects >= self.config.max_test_rejects + { + test_data.failure = Some(err); + break 'stop; } } } diff --git a/crates/fmt/README.md b/crates/fmt/README.md index 81515220e40c0..59bba65cf5f50 100644 --- a/crates/fmt/README.md +++ b/crates/fmt/README.md @@ -115,17 +115,20 @@ The formatter supports multiple configuration options defined in `foundry.toml`. | `style` | `space` | The style of indentation. Options: `space`, `tab`. | | `bracket_spacing` | `false` | Print spaces between brackets. | | `int_types` | `long` | Style for `uint256`/`int256` types. Options: `long`, `short`, `preserve`. | -| `multiline_func_header` | `attributes_first` | The style of multiline function headers. Options: `attributes_first`, `params_first`, `params_first_multi`, `all`, `all_params`. | +| `multiline_func_header` | `attributes_first` | The style of multiline function headers. Options: `attributes_first`, `params_always`, `params_first_multi`, `all`, `all_params`. | +| `prefer_compact` | `all` | Style that determines if a broken list, should keep its elements together on their own line, before breaking individually. Options: `none`, `calls`, `events`, `errors`, `events_errors`, `all`. | | `quote_style` | `double` | The style of quotation marks. Options: `double`, `single`, `preserve`. | | `number_underscore` | `preserve` | The style of underscores in number literals. Options: `preserve`, `remove`, `thousands`. | | `hex_underscore` | `remove` | The style of underscores in hex literals. Options: `preserve`, `remove`, `bytes`. | | `single_line_statement_blocks` | `preserve` | The style of single-line blocks in statements. Options: `preserve`, `single`, `multi`. | | `override_spacing` | `false` | Print a space in the `override` attribute. | | `wrap_comments` | `false` | Wrap comments when `line_length` is reached. | +| `docs_style` | `preserve` | Enforces the style of doc (natspec) comments. Options: `preserve`, `line`, `block`. | | `ignore` | `[]` | Globs to ignore. | | `contract_new_lines` | `false` | Add a new line at the start and end of contract declarations. | | `sort_imports` | `false` | Sort import statements alphabetically in groups. A group is a set of imports separated by a newline. | | `pow_no_space` | `false` | Suppress spaces around the power operator (`**`). | +| `single_line_imports` | `false` | Keep single imports on a single line, even if they exceed the line length limit. | ### Inline Configuration diff --git a/crates/fmt/src/state/common.rs b/crates/fmt/src/state/common.rs index 4930875f2ceeb..97b5b7b0b91ec 100644 --- a/crates/fmt/src/state/common.rs +++ b/crates/fmt/src/state/common.rs @@ -284,6 +284,7 @@ impl<'ast> State<'_, 'ast> { values: &[T], mut get_span: S, format: ListFormat, + manual_opening: bool, ) -> bool where S: FnMut(&T) -> Span, @@ -314,6 +315,14 @@ impl<'ast> State<'_, 'ast> { } }; + // If manual opening flag is passed, we simply force the break, and skip the comment. + // It will be dealt with when printing the item in the main loop of `commasep`. + if manual_opening { + self.hardbreak(); + self.s.offset(self.ind); + return true; + } + let cmnt_config = if format.with_delimiters { CommentConfig::skip_ws().mixed_no_break().mixed_prev_space() } else { @@ -377,23 +386,37 @@ impl<'ast> State<'_, 'ast> { return; } - let first = get_span(&values[0]); - // we can't simply check `peek_comment_before(pos_hi)` cause we would also account for + // We can't simply check `peek_comment_before(pos_hi)` cause we would also account for // comments in the child expression, and those don't matter. - let has_comments = self.peek_comment_before(first.lo()).is_some() - || self.peek_comment_between(first.hi(), pos_hi).is_some(); - let is_single_without_cmnts = values.len() == 1 && !format.break_single && !has_comments; + let has_comments = + // check for comments before the first element + self.peek_comment_before(get_span(&values[0]).lo()).is_some() || + // check for comments between elements + values.windows(2).any(|w| self.peek_comment_between(get_span(&w[0]).hi(), get_span(&w[1]).lo()).is_some()) || + // check for comments after the last element + self.peek_comment_between(get_span(values.last().unwrap()).hi(), pos_hi).is_some(); + + // For calls with opts and args, which should break consistently, we need to skip the + // wrapping cbox to prioritize call args breaking before the call opts. Because of that, we + // must manually offset the breaks between args, so that they are properly indented. + let manual_opening = + format.is_consistent() && !format.with_delimiters && self.call_with_opts_and_args; + // When there are comments, we can preserve the cbox, as they will make it break + let manual_offset = !has_comments && manual_opening; + let is_single_without_cmnts = values.len() == 1 && !format.break_single && !has_comments; let skip_first_break = if format.with_delimiters || format.is_inline() { self.s.cbox(if format.no_ind { 0 } else { self.ind }); if is_single_without_cmnts { true } else { - self.commasep_opening_logic(values, &mut get_span, format) + self.commasep_opening_logic(values, &mut get_span, format, manual_opening) } } else { - let res = self.commasep_opening_logic(values, &mut get_span, format); - self.s.cbox(if format.no_ind { 0 } else { self.ind }); + let res = self.commasep_opening_logic(values, &mut get_span, format, manual_opening); + if !manual_offset { + self.s.cbox(if format.no_ind { 0 } else { self.ind }); + } res }; @@ -403,6 +426,9 @@ impl<'ast> State<'_, 'ast> { self.nbsp(); } else if !skip_first_break && !format.is_inline() { format.print_break(true, values.len(), &mut self.s); + if manual_offset { + self.s.offset(self.ind); + } } if format.is_compact() && !(format.breaks_with_comments() && has_comments) { @@ -471,6 +497,9 @@ impl<'ast> State<'_, 'ast> { && !next_span.is_dummy() { format.print_break(false, values.len(), &mut self.s); + if manual_offset { + self.s.offset(self.ind); + } } } @@ -493,7 +522,9 @@ impl<'ast> State<'_, 'ast> { self.word(sym); } - self.end(); + if !manual_offset { + self.end(); + } self.cursor.advance_to(pos_hi, true); if last_delimiter_break { @@ -510,7 +541,9 @@ impl<'ast> State<'_, 'ast> { for (pos, ident) in path.segments().iter().delimited() { self.print_ident(ident); if !pos.is_last { - self.zerobreak(); + if !self.emit_or_revert { + self.zerobreak(); + } self.word("."); } } @@ -572,7 +605,7 @@ impl<'ast> State<'_, 'ast> { self.s.offset(offset); } } else if style.is_isolated() { - self.print_sep_unhandled(Separator::Space); + self.print_sep_unhandled(Separator::Hardbreak); self.s.offset(offset); } } @@ -784,6 +817,10 @@ impl ListFormat { if let ListFormatKind::Yul { sym_post, .. } = self.kind { sym_post } else { None } } + pub(crate) fn is_consistent(&self) -> bool { + matches!(self.kind, ListFormatKind::Consistent) + } + pub(crate) fn is_compact(&self) -> bool { matches!(self.kind, ListFormatKind::Compact) } diff --git a/crates/fmt/src/state/mod.rs b/crates/fmt/src/state/mod.rs index c0cecb7afa85b..9bbe2f3bda6e3 100644 --- a/crates/fmt/src/state/mod.rs +++ b/crates/fmt/src/state/mod.rs @@ -8,7 +8,7 @@ use foundry_common::{ comments::{Comment, CommentStyle, Comments, estimate_line_width, line_with_tabs}, iter::IterDelimited, }; -use foundry_config::fmt::IndentStyle; +use foundry_config::fmt::{DocCommentStyle, IndentStyle}; use solar::parse::{ ast::{self, Span}, interface::{BytePos, SourceMap}, @@ -126,6 +126,8 @@ pub(super) struct State<'sess, 'ast> { return_bin_expr: bool, // Whether inside a call with call options and at least one argument. call_with_opts_and_args: bool, + // Whether to skip the index soft breaks because the callee fits inline. + skip_index_break: bool, // Whether inside an `emit` or `revert` call with a qualified path, or not. emit_or_revert: bool, // Whether inside a variable initialization expression, or not. @@ -219,6 +221,7 @@ impl<'sess> State<'sess, '_> { contract: None, single_line_stmt: None, call_with_opts_and_args: false, + skip_index_break: false, binary_expr: None, return_bin_expr: false, emit_or_revert: false, @@ -247,11 +250,17 @@ impl<'sess> State<'sess, '_> { self.has_crlf && self.char_at(self.cursor.pos) == Some('\r') } + /// Computes the space left, bounded by the max space left. fn space_left(&self) -> usize { - std::cmp::min( - self.s.space_left(), - self.config.line_length.saturating_sub(self.block_depth * self.config.tab_width), - ) + std::cmp::min(self.s.space_left(), self.max_space_left(0)) + } + + /// Computes the maximum space left given the context information available: + /// `block_depth`, `tab_width`, and a user-defined unavailable size `prefix_len`. + fn max_space_left(&self, prefix_len: usize) -> usize { + self.config + .line_length + .saturating_sub(self.block_depth * self.config.tab_width + prefix_len) } fn break_offset_if_not_bol(&mut self, n: usize, off: isize, search: bool) { @@ -495,9 +504,30 @@ impl<'sess> State<'sess, '_> { let config_cache = config; let mut buffered_blank = None; while self.peek_comment().is_some_and(|c| c.pos() < pos) { - let cmnt = self.next_comment().unwrap(); + let mut cmnt = self.next_comment().unwrap(); let style_cache = cmnt.style; + // Merge consecutive line doc comments when converting to block style + if self.config.docs_style == foundry_config::fmt::DocCommentStyle::Block + && cmnt.is_doc + && cmnt.kind == ast::CommentKind::Line + { + let mut ref_line = self.sm.lookup_char_pos(cmnt.span.hi()).line; + while let Some(next_cmnt) = self.peek_comment() { + if !next_cmnt.is_doc + || next_cmnt.kind != ast::CommentKind::Line + || ref_line + 1 != self.sm.lookup_char_pos(next_cmnt.span.lo()).line + { + break; + } + + let next_to_merge = self.next_comment().unwrap(); + cmnt.lines.extend(next_to_merge.lines); + cmnt.span = cmnt.span.to(next_to_merge.span); + ref_line += 1; + } + } + // Ensure breaks are never skipped when there are multiple comments if self.peek_comment_before(pos).is_some() { config.iso_no_break = false; @@ -710,6 +740,11 @@ impl<'sess> State<'sess, '_> { fn print_comment(&mut self, mut cmnt: Comment, mut config: CommentConfig) { self.cursor.advance_to(cmnt.span.hi(), true); + + if cmnt.is_doc { + cmnt = style_doc_comment(self.config.docs_style, cmnt); + } + match cmnt.style { CommentStyle::Mixed => { let Some(prefix) = cmnt.prefix() else { return }; @@ -835,15 +870,14 @@ impl<'sess> State<'sess, '_> { if !self.config.wrap_comments && cmnt.lines.len() == 1 { self.word(cmnt.lines.pop().unwrap()); } else if self.config.wrap_comments { - config.offset = self.ind; + if cmnt.is_doc || matches!(cmnt.kind, ast::CommentKind::Line) { + config.offset = 0; + } else { + config.offset = self.ind; + } for (lpos, line) in cmnt.lines.into_iter().delimited() { if !line.is_empty() { - self.print_wrapped_line( - &line, - prefix, - if cmnt.is_doc { 0 } else { config.offset }, - cmnt.is_doc, - ); + self.print_wrapped_line(&line, prefix, config.offset, cmnt.is_doc); } if !lpos.is_last { config.hardbreak(&mut self.s); @@ -1112,3 +1146,47 @@ fn snippet_with_tabs(s: String, tab_width: usize) -> String { formatted } + +/// Formats a doc comment with the requested style. +/// +/// NOTE: assumes comments have already been normalized. +fn style_doc_comment(style: DocCommentStyle, mut cmnt: Comment) -> Comment { + match style { + DocCommentStyle::Line if cmnt.kind == ast::CommentKind::Block => { + let mut new_lines = Vec::new(); + for (pos, line) in cmnt.lines.iter().delimited() { + if pos.is_first || pos.is_last { + // Skip the opening '/**' and closing '*/' lines + continue; + } + + // Convert ' * {content}' to '/// {content}' + let trimmed = line.trim_start(); + if let Some(content) = trimmed.strip_prefix('*') { + new_lines.push(format!("///{content}")); + } else if !trimmed.is_empty() { + new_lines.push(format!("/// {trimmed}")); + } + } + + cmnt.lines = new_lines; + cmnt.kind = ast::CommentKind::Line; + cmnt + } + DocCommentStyle::Block if cmnt.kind == ast::CommentKind::Line => { + let mut new_lines = vec!["/**".to_string()]; + + for line in &cmnt.lines { + // Convert '/// {content}' to ' * {content}' + new_lines.push(format!(" *{content}", content = &line[3..])) + } + + new_lines.push(" */".to_string()); + cmnt.lines = new_lines; + cmnt.kind = ast::CommentKind::Block; + cmnt + } + // Otherwise, no conversion needed. + _ => cmnt, + } +} diff --git a/crates/fmt/src/state/sol.rs b/crates/fmt/src/state/sol.rs index d9569543c6d70..e20db98bd430a 100644 --- a/crates/fmt/src/state/sol.rs +++ b/crates/fmt/src/state/sol.rs @@ -215,9 +215,19 @@ impl<'ast> State<'_, 'ast> { } ast::ImportItems::Aliases(aliases) => { - self.s.cbox(self.ind); - self.word("{"); - self.braces_break(); + // Check if we should keep single imports on one line + let use_single_line = self.config.single_line_imports && aliases.len() == 1; + + if use_single_line { + self.word("{"); + if self.config.bracket_spacing { + self.nbsp(); + } + } else { + self.s.cbox(self.ind); + self.word("{"); + self.braces_break(); + } if self.config.sort_imports { let mut sorted: Vec<_> = aliases.iter().collect(); @@ -227,10 +237,17 @@ impl<'ast> State<'_, 'ast> { self.print_commasep_aliases(aliases.iter()); }; - self.braces_break(); - self.s.offset(-self.ind); - self.word("}"); - self.end(); + if use_single_line { + if self.config.bracket_spacing { + self.nbsp(); + } + self.word("}"); + } else { + self.braces_break(); + self.s.offset(-self.ind); + self.word("}"); + self.end(); + } self.word(" from "); self.print_ast_str_lit(path); } @@ -474,12 +491,12 @@ impl<'ast> State<'_, 'ast> { let params_format = match header_style { MultilineFuncHeaderStyle::ParamsFirst => ListFormat::always_break(), MultilineFuncHeaderStyle::All - if header.parameters.len() > 1 && !self.can_header_be_inlined(header) => + if header.parameters.len() > 1 && !self.can_header_be_inlined(func) => { ListFormat::always_break() } MultilineFuncHeaderStyle::AllParams - if !header.parameters.is_empty() && !self.can_header_be_inlined(header) => + if !header.parameters.is_empty() && !self.can_header_be_inlined(func) => { ListFormat::always_break() } @@ -533,7 +550,7 @@ impl<'ast> State<'_, 'ast> { let attrib_box = self.config.multiline_func_header.params_first() || (self.config.multiline_func_header.attrib_first() - && !self.can_header_params_be_inlined(header)); + && !self.can_header_params_be_inlined(func)); if attrib_box { self.s.cbox(0); } @@ -725,7 +742,15 @@ impl<'ast> State<'_, 'ast> { let ast::ItemError { name, parameters } = err; self.word("error "); self.print_ident(name); - self.print_parameter_list(parameters, parameters.span, ListFormat::compact()); + self.print_parameter_list( + parameters, + parameters.span, + if self.config.prefer_compact.errors() { + ListFormat::compact() + } else { + ListFormat::consistent() + }, + ); self.word(";"); } @@ -733,7 +758,15 @@ impl<'ast> State<'_, 'ast> { let ast::ItemEvent { name, parameters, anonymous } = event; self.word("event "); self.print_ident(name); - self.print_parameter_list(parameters, parameters.span, ListFormat::compact().break_cmnts()); + self.print_parameter_list( + parameters, + parameters.span, + if self.config.prefer_compact.events() { + ListFormat::compact().break_cmnts() + } else { + ListFormat::consistent().break_cmnts() + }, + ); if *anonymous { self.word(" anonymous"); } @@ -803,24 +836,48 @@ impl<'ast> State<'_, 'ast> { self.s.offset(self.ind); self.print_expr(rhs); } - ast::ExprKind::Binary(_, op, _) => { - // Binary expressions: check if we need to break and indent - if force_break || self.estimate_lhs_size(rhs, op) + lhs_size > space_left { - if !self.is_bol_or_only_ind() { + ast::ExprKind::Binary(lhs, op, _) => { + let print_inline = |this: &mut Self| { + this.print_sep(Separator::Nbsp); + this.neverbreak(); + this.print_expr(rhs); + }; + let print_with_break = |this: &mut Self, force_break: bool| { + if !this.is_bol_or_only_ind() { if force_break { - self.print_sep(Separator::Hardbreak); + this.print_sep(Separator::Hardbreak); } else { - self.print_sep(Separator::Space); + this.print_sep(Separator::Space); } } - self.s.offset(self.ind); - self.s.ibox(self.ind); - self.print_expr(rhs); - self.end(); - } else { - self.print_sep(Separator::Nbsp); - self.neverbreak(); - self.print_expr(rhs); + this.s.offset(this.ind); + this.s.ibox(this.ind); + this.print_expr(rhs); + this.end(); + }; + + // Binary expressions: check if we need to break and indent + if force_break { + print_with_break(self, true); + } else if self.estimate_lhs_size(rhs, op) + lhs_size > space_left { + if has_complex_successor(&rhs.kind, true) + && get_callee_head_size(lhs) + lhs_size <= space_left + { + // Keep complex exprs (where callee fits) inline, as they will have breaks + if matches!(lhs.kind, ast::ExprKind::Call(..)) { + self.s.ibox(-self.ind); + print_inline(self); + self.end(); + } else { + print_inline(self); + } + } else { + print_with_break(self, false); + } + } + // Otherwise, if expr fits, ensure no breaks + else { + print_inline(self); } } _ => { @@ -1252,8 +1309,15 @@ impl<'ast> State<'_, 'ast> { self.call_with_opts_and_args = cache; } ast::ExprKind::CallOptions(expr, named_args) => { + // the flag is only meant to be used to format the call args + let cache = self.call_with_opts_and_args; + self.call_with_opts_and_args = false; + self.print_expr(expr); self.print_named_args(named_args, span.hi()); + + // restore cached value + self.call_with_opts_and_args = cache; } ast::ExprKind::Delete(expr) => { self.word("delete "); @@ -1274,11 +1338,10 @@ impl<'ast> State<'_, 'ast> { MemberOrCallArgs::Member(self.estimate_size(ident.span)), |s| { s.print_trailing_comment(member_expr.span.hi(), Some(ident.span.lo())); - if !matches!( - member_expr.kind, - ast::ExprKind::Ident(_) | ast::ExprKind::Type(_) - ) { - s.zerobreak(); + match member_expr.kind { + ast::ExprKind::Ident(_) | ast::ExprKind::Type(_) => (), + ast::ExprKind::Index(..) if s.skip_index_break => (), + _ => s.zerobreak(), } s.word("."); s.print_ident(ident); @@ -1442,10 +1505,16 @@ impl<'ast> State<'_, 'ast> { self.s.cbox(self.ind); let mut skip_break = false; - + let mut zerobreak = |this: &mut Self| { + if this.skip_index_break { + skip_break = true; + } else { + this.zerobreak(); + } + }; match kind { ast::IndexKind::Index(Some(inner_expr)) => { - self.zerobreak(); + zerobreak(self); self.print_expr(inner_expr); } ast::IndexKind::Index(None) => {} @@ -1455,11 +1524,11 @@ impl<'ast> State<'_, 'ast> { .print_comments(start_expr.span.lo(), CommentConfig::skip_ws()) .is_none_or(|s| s.is_mixed()) { - self.zerobreak(); + zerobreak(self); } self.print_expr(start_expr); } else { - self.zerobreak(); + zerobreak(self); } self.word(":"); @@ -1467,7 +1536,7 @@ impl<'ast> State<'_, 'ast> { if let Some(end_expr) = end { self.s.ibox(self.ind); if start.is_some() { - self.zerobreak(); + zerobreak(self); } self.print_comments( end_expr.span.lo(), @@ -1528,34 +1597,35 @@ impl<'ast> State<'_, 'ast> { self.s.cbox(self.ind); self.s.ibox(0); - let mut print_ternary_expr = - |span_lo, prefix: Option<&'static str>, expr: &'ast ast::Expr<'ast>| { - match prefix { - Some(prefix) => { - if self.peek_comment_before(span_lo).is_some() { - self.space(); - } - self.print_comments(span_lo, CommentConfig::skip_ws()); - self.end(); - if !self.is_bol_or_only_ind() { - self.space(); - } - self.s.ibox(0); - self.word(prefix); + let print_sub_expr = |this: &mut Self, span_lo, prefix, expr: &'ast ast::Expr<'ast>| { + match prefix { + Some(prefix) => { + if this.peek_comment_before(span_lo).is_some() { + this.space(); } - None => { - self.print_comments(expr.span.lo(), CommentConfig::skip_ws()); + this.print_comments(span_lo, CommentConfig::skip_ws()); + this.end(); + if !this.is_bol_or_only_ind() { + this.space(); } - }; - self.print_expr(expr); + this.s.ibox(0); + this.word(prefix); + } + None => { + this.print_comments(expr.span.lo(), CommentConfig::skip_ws()); + } }; + this.print_expr(expr); + }; // conditional expression - print_ternary_expr(then.span.lo(), None, cond); + self.s.ibox(-self.ind); + print_sub_expr(self, then.span.lo(), None, cond); + self.end(); // then expression - print_ternary_expr(then.span.lo(), Some("? "), then); + print_sub_expr(self, then.span.lo(), Some("? "), then); // else expression - print_ternary_expr(els.span.lo(), Some(": "), els); + print_sub_expr(self, els.span.lo(), Some(": "), els); self.end(); self.neverbreak(); @@ -1596,7 +1666,7 @@ impl<'ast> State<'_, 'ast> { } } - let mut extra_box = false; + let (mut extra_box, skip_cache) = (false, self.skip_index_break); let parent_is_chain = self.call_stack.last().copied().is_some_and(|call| call.is_chained()); if !parent_is_chain { // Estimate sizes of callee and optional member @@ -1610,7 +1680,7 @@ impl<'ast> State<'_, 'ast> { let callee_fits_line = self.space_left() > callee_size + 1; let total_fits_line = self.space_left() > expr_size + member_or_args.size() + 2; - let no_mixed_comment = + let no_cmnt_or_mixed = self.peek_comment_before(child_expr.span.hi()).is_none_or(|c| c.style.is_mixed()); // If call with options, add an extra box to prioritize breaking the call args @@ -1620,12 +1690,13 @@ impl<'ast> State<'_, 'ast> { } if !is_call_chain(&child_expr.kind, true) - && no_mixed_comment + && (no_cmnt_or_mixed || matches!(&child_expr.kind, ast::ExprKind::CallOptions(..))) && callee_fits_line && (member_depth(0, child_expr) < 2 // calls with cmnts between the args always break || (total_fits_line && !member_or_args.has_comments())) { + self.skip_index_break = true; self.cbox(0); } else { self.s.ibox(self.ind); @@ -1650,6 +1721,11 @@ impl<'ast> State<'_, 'ast> { } self.end(); } + + // Restore cache + if self.skip_index_break { + self.skip_index_break = skip_cache; + } } fn print_call_args( @@ -1690,7 +1766,7 @@ impl<'ast> State<'_, 'ast> { } fn print_named_args(&mut self, args: &'ast [ast::NamedArg<'ast>], pos_hi: BytePos) { - let list_format = match (self.config.bracket_spacing, self.config.call_compact_args) { + let list_format = match (self.config.bracket_spacing, self.config.prefer_compact.calls()) { (false, true) => ListFormat::compact(), (false, false) => ListFormat::consistent(), (true, true) => ListFormat::compact().with_space(), @@ -1727,7 +1803,7 @@ impl<'ast> State<'_, 'ast> { .break_cmnts() .break_single(true) .without_ind(self.call_stack.is_chain()) - .with_delimiters(!(self.emit_or_revert || self.call_with_opts_and_args)), + .with_delimiters(!self.call_with_opts_and_args), ); } else if self.config.bracket_spacing { self.nbsp(); @@ -1828,7 +1904,7 @@ impl<'ast> State<'_, 'ast> { _ = self.handle_span(self.cursor.span(span.lo()), false); if !self.handle_span(span.until(block.span), false) { self.cursor.advance_to(span.lo(), true); - self.print_word("assembly "); + self.print_word("assembly "); // 9 chars if let Some(dialect) = dialect { self.print_ast_str_lit(dialect); self.print_sep(Separator::Nbsp); @@ -1845,7 +1921,7 @@ impl<'ast> State<'_, 'ast> { self.print_sep(Separator::Nbsp); } } - self.print_yul_block(block, block.span, false); + self.print_yul_block(block, block.span, false, 9); } /// Prints a multiple-variable declaration with a single initializer expression, @@ -2184,7 +2260,9 @@ impl<'ast> State<'_, 'ast> { } self.print_word("{"); self.end(); - self.print_trailing_comment_no_break(catch_span.lo(), None); + if !block.is_empty() { + self.print_trailing_comment_no_break(catch_span.lo(), None); + } self.print_block_without_braces(block, catch_span.hi(), Some(self.ind)); if self.cursor.enabled || self.cursor.pos < try_span.hi() { self.print_word("}"); @@ -2251,17 +2329,14 @@ impl<'ast> State<'_, 'ast> { self.nbsp(); }; self.s.cbox(0); - self.print_path(path, false); self.emit_or_revert = path.segments().len() > 1; - self.print_call_args( - args, - if self.config.call_compact_args { - ListFormat::compact().break_cmnts().with_delimiters(args.len() == 1) - } else { - ListFormat::consistent().break_cmnts().with_delimiters(args.len() == 1) - }, - path.to_string().len(), - ); + self.print_path(path, false); + let format = if self.config.prefer_compact.calls() { + ListFormat::compact() + } else { + ListFormat::consistent() + }; + self.print_call_args(args, format.break_cmnts(), path.to_string().len()); self.emit_or_revert = false; self.end(); } @@ -2485,36 +2560,58 @@ impl<'ast> State<'_, 'ast> { els_opt.is_none_or(|els| self.is_inline_stmt(els, 6)) } - fn can_header_be_inlined(&mut self, header: &ast::FunctionHeader<'_>) -> bool { - const FUNCTION: usize = 8; + fn can_header_be_inlined(&mut self, func: &ast::ItemFunction<'_>) -> bool { + self.estimate_header_size(func) <= self.space_left() + } + + fn can_header_params_be_inlined(&mut self, func: &ast::ItemFunction<'_>) -> bool { + self.estimate_header_params_size(func) <= self.space_left() + } + + fn estimate_header_size(&mut self, func: &ast::ItemFunction<'_>) -> usize { + let ast::ItemFunction { kind: _, ref header, ref body, body_span: _ } = *func; // ' ' + visibility let visibility = header.visibility.map_or(0, |v| self.estimate_size(v.span) + 1); // ' ' + state mutability let mutability = header.state_mutability.map_or(0, |sm| self.estimate_size(sm.span) + 1); // ' ' + modifier + (' ' + modifier) - let modifiers = - header.modifiers.iter().fold(0, |len, m| len + self.estimate_size(m.span())) + 1; + let m = header.modifiers.iter().fold(0, |len, m| len + self.estimate_size(m.span())); + let modifiers = if m != 0 { m + 1 } else { 0 }; // ' ' + override let override_ = header.override_.as_ref().map_or(0, |o| self.estimate_size(o.span) + 1); + // ' ' + virtual + let virtual_ = if header.virtual_.is_none() { 0 } else { 8 }; // ' returns(' + var + (', ' + var) + ')' let returns = header.returns.as_ref().map_or(0, |ret| { ret.vars .iter() - .fold(0, |len, p| if len != 0 { len + 2 } else { 8 } + self.estimate_size(p.span)) + .fold(0, |len, p| if len != 0 { len + 2 } else { 10 } + self.estimate_size(p.span)) }); + // ' {' or ';' + let end = if body.is_some() { 2 } else { 1 }; - FUNCTION - + self.estimate_header_params_size(header) + self.estimate_header_params_size(func) + visibility + mutability + modifiers + override_ + + virtual_ + returns - <= self.space_left() + + end } - fn estimate_header_params_size(&mut self, header: &ast::FunctionHeader<'_>) -> usize { + fn estimate_header_params_size(&mut self, func: &ast::ItemFunction<'_>) -> usize { + let ast::ItemFunction { kind, ref header, body: _, body_span: _ } = *func; + + let kw = match kind { + ast::FunctionKind::Constructor => 11, // 'constructor' + ast::FunctionKind::Function => 9, // 'function ' + ast::FunctionKind::Modifier => 9, // 'modifier ' + ast::FunctionKind::Fallback => 8, // 'fallback' + ast::FunctionKind::Receive => 7, // 'receive' + }; + // '(' + param + (', ' + param) + ')' let params = header .parameters @@ -2522,12 +2619,7 @@ impl<'ast> State<'_, 'ast> { .iter() .fold(0, |len, p| if len != 0 { len + 2 } else { 2 } + self.estimate_size(p.span)); - // 'function ' + name + ' ' + params - 9 + header.name.map_or(0, |name| self.estimate_size(name.span) + 1) + params - } - - fn can_header_params_be_inlined(&mut self, header: &ast::FunctionHeader<'_>) -> bool { - self.estimate_header_params_size(header) <= self.space_left() + kw + header.name.map_or(0, |name| self.estimate_size(name.span)) + std::cmp::max(2, params) } fn estimate_lhs_size(&self, expr: &ast::Expr<'_>, parent_op: &ast::BinOp) -> usize { @@ -2784,6 +2876,7 @@ fn has_complex_successor(expr_kind: &ast::ExprKind<'_>, left: bool) -> bool { } ast::ExprKind::Unary(_, expr) => has_complex_successor(&expr.kind, left), ast::ExprKind::Lit(..) | ast::ExprKind::Ident(_) => false, + ast::ExprKind::Tuple(..) => false, _ => true, } } @@ -2857,6 +2950,16 @@ pub(super) fn get_callee_head_size(callee: &ast::Expr<'_>) -> usize { ast::ExprKind::Type(ast::Type { kind: ast::TypeKind::Elementary(ty), .. }) => { ty.to_abi_str().len() } + ast::ExprKind::Index(base, idx) => { + let idx_len = match idx { + ast::IndexKind::Index(expr) => expr.as_ref().map_or(0, |e| get_callee_head_size(e)), + ast::IndexKind::Range(e1, e2) => { + 1 + e1.as_ref().map_or(0, |e| get_callee_head_size(e)) + + e2.as_ref().map_or(0, |e| get_callee_head_size(e)) + } + }; + get_callee_head_size(base) + 2 + idx_len + } ast::ExprKind::Member(base, member_ident) => { match &base.kind { ast::ExprKind::Ident(..) | ast::ExprKind::Type(..) => { @@ -2872,8 +2975,123 @@ pub(super) fn get_callee_head_size(callee: &ast::Expr<'_>) -> usize { _ => member_ident.as_str().len(), } } + ast::ExprKind::Binary(lhs, _, _) => get_callee_head_size(lhs), // If the callee is not an identifier or member access, it has no "head" _ => 0, } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{FormatterConfig, InlineConfig}; + use foundry_common::comments::Comments; + use solar::{ + interface::{Session, source_map::FileName}, + sema::Compiler, + }; + use std::sync::Arc; + + /// This helper extracts function headers from the AST and passes them to the test function. + fn parse_and_test(source: &str, test_fn: F) + where + F: FnOnce(&mut State<'_, '_>, &ast::ItemFunction<'_>) + Send, + { + let session = Session::builder().with_buffer_emitter(Default::default()).build(); + let mut compiler = Compiler::new(session); + + compiler + .enter_mut(|c| -> solar::interface::Result<()> { + let mut pcx = c.parse(); + pcx.set_resolve_imports(false); + + // Create a source file using stdin as the filename + let file = c + .sess() + .source_map() + .new_source_file(FileName::Stdin, source) + .map_err(|e| c.sess().dcx.err(e.to_string()).emit())?; + + pcx.add_file(file.clone()); + pcx.parse(); + c.dcx().has_errors()?; + + // Get AST from parsed source and setup the formatter + let gcx = c.gcx(); + let (_, source_obj) = gcx.get_ast_source(&file.name).expect("Failed to get AST"); + let ast = source_obj.ast.as_ref().expect("No AST found"); + let comments = + Comments::new(&source_obj.file, gcx.sess.source_map(), true, false, None); + let config = Arc::new(FormatterConfig::default()); + let inline_config = InlineConfig::default(); + let mut state = State::new(gcx.sess.source_map(), config, inline_config, comments); + + // Extract the first function header (either top-level or inside a contract) + let func = ast + .items + .iter() + .find_map(|item| match &item.kind { + ast::ItemKind::Function(func) => Some(func), + ast::ItemKind::Contract(contract) => { + contract.body.iter().find_map(|contract_item| { + match &contract_item.kind { + ast::ItemKind::Function(func) => Some(func), + _ => None, + } + }) + } + _ => None, + }) + .expect("No function found in source"); + + // Run the closure + test_fn(&mut state, func); + + Ok(()) + }) + .expect("Test failed"); + } + + #[test] + fn test_estimate_header_sizes() { + let test_cases = [ + ("function foo();", 14, 15), + ("function foo() {}", 14, 16), + ("function foo() public {}", 14, 23), + ("function foo(uint256 a) public {}", 23, 32), + ("function foo(uint256 a, address b, bool c) public {}", 42, 51), + ("function foo() public pure {}", 14, 28), + ("function foo() public virtual {}", 14, 31), + ("function foo() public override {}", 14, 32), + ("function foo() public onlyOwner {}", 14, 33), + ("function foo() public returns(uint256) {}", 14, 40), + ("function foo() public returns(uint256, address) {}", 14, 49), + ("function foo(uint256 a) public virtual override returns(uint256) {}", 23, 66), + ("function foo() external payable {}", 14, 33), + // other function types + ("contract C { constructor() {} }", 13, 15), + ("contract C { constructor(uint256 a) {} }", 22, 24), + ("contract C { modifier onlyOwner() {} }", 20, 22), + ("contract C { modifier onlyRole(bytes32 role) {} }", 31, 33), + ("contract C { fallback() external payable {} }", 10, 29), + ("contract C { receive() external payable {} }", 9, 28), + ]; + + for (source, expected_params, expected_header) in &test_cases { + parse_and_test(source, |state, func| { + let params_size = state.estimate_header_params_size(func); + assert_eq!( + params_size, *expected_params, + "Failed params size: expected {expected_params}, got {params_size} for source: {source}", + ); + + let header_size = state.estimate_header_size(func); + assert_eq!( + header_size, *expected_header, + "Failed header size: expected {expected_header}, got {header_size} for source: {source}", + ); + }); + } + } +} diff --git a/crates/fmt/src/state/yul.rs b/crates/fmt/src/state/yul.rs index 120d98312e0b2..0f973624bf9ec 100644 --- a/crates/fmt/src/state/yul.rs +++ b/crates/fmt/src/state/yul.rs @@ -26,11 +26,12 @@ impl<'ast> State<'_, 'ast> { } match kind { - yul::StmtKind::Block(stmts) => self.print_yul_block(stmts, span, false), + yul::StmtKind::Block(stmts) => self.print_yul_block(stmts, span, false, 0), yul::StmtKind::AssignSingle(path, expr) => { self.print_path(path, false); self.word(" := "); self.neverbreak(); + self.cursor.advance_to(expr.span.lo(), self.cursor.enabled); self.print_yul_expr(expr); } yul::StmtKind::AssignMulti(paths, expr_call) => { @@ -53,30 +54,30 @@ impl<'ast> State<'_, 'ast> { } yul::StmtKind::Expr(expr_call) => self.print_yul_expr(expr_call), yul::StmtKind::If(expr, stmts) => { - self.word("if "); + self.print_word("if "); // 3 chars self.print_yul_expr(expr); - self.nbsp(); - self.print_yul_block(stmts, span, false); + self.nbsp(); // 1 char + self.print_yul_block(stmts, span, false, 4 + self.estimate_size(expr.span)); } yul::StmtKind::For(yul::StmtFor { init, cond, step, body }) => { self.ibox(0); - self.word("for "); - self.print_yul_block(init, init.span, false); + self.print_word("for "); // 4 chars + self.print_yul_block(init, init.span, false, 4); self.space(); self.print_yul_expr(cond); self.space(); - self.print_yul_block(step, step.span, false); + self.print_yul_block(step, step.span, false, 0); self.space(); - self.print_yul_block(body, body.span, false); + self.print_yul_block(body, body.span, false, 0); self.end(); } yul::StmtKind::Switch(yul::StmtSwitch { selector, cases }) => { - self.word("switch "); + self.print_word("switch "); self.print_yul_expr(selector); self.print_trailing_comment(selector.span.hi(), None); @@ -88,7 +89,7 @@ impl<'ast> State<'_, 'ast> { constant.span.lo(), CommentConfig::default().mixed_prev_space(), ); - self.word("case "); + self.print_word("case "); self.print_lit_yul(constant); self.nbsp(); } else { @@ -96,16 +97,16 @@ impl<'ast> State<'_, 'ast> { body.span.lo(), CommentConfig::default().mixed_prev_space(), ); - self.word("default "); + self.print_word("default "); } - self.print_yul_block(body, *span, false); + self.print_yul_block(body, *span, false, 0); self.print_trailing_comment(selector.span.hi(), None); } } - yul::StmtKind::Leave => self.word("leave"), - yul::StmtKind::Break => self.word("break"), - yul::StmtKind::Continue => self.word("continue"), + yul::StmtKind::Leave => self.print_word("leave"), + yul::StmtKind::Break => self.print_word("break"), + yul::StmtKind::Continue => self.print_word("continue"), yul::StmtKind::FunctionDef(func) => { let yul::Function { name, parameters, returns, body } = func; let params_hi = parameters @@ -116,7 +117,7 @@ impl<'ast> State<'_, 'ast> { self.cbox(0); self.s.ibox(0); - self.word("function "); + self.print_word("function "); self.print_ident(name); self.print_tuple( parameters, @@ -143,12 +144,12 @@ impl<'ast> State<'_, 'ast> { ); } self.end(); - self.print_yul_block(body, span, skip_opening_brace); + self.print_yul_block(body, span, skip_opening_brace, 0); self.end(); } yul::StmtKind::VarDecl(idents, expr) => { self.s.ibox(self.ind); - self.word("let "); + self.print_word("let "); self.commasep( idents, stmt.span.lo(), @@ -158,7 +159,7 @@ impl<'ast> State<'_, 'ast> { ListFormat::consistent(), ); if let Some(expr) = expr { - self.word(" :="); + self.print_word(" :="); self.space(); self.print_yul_expr(expr); } @@ -201,6 +202,7 @@ impl<'ast> State<'_, 'ast> { block: &'ast yul::Block<'ast>, span: Span, skip_opening_brace: bool, + prefix_len: usize, ) { if self.handle_span(span, false) { return; @@ -210,9 +212,15 @@ impl<'ast> State<'_, 'ast> { self.print_word("{"); } - let can_inline_block = block.len() <= 1 - && !self.is_multiline_yul_block(block) - && self.estimate_size(block.span) <= self.space_left(); + let can_inline_block = if block.len() <= 1 && !self.is_multiline_yul_block(block) { + if self.max_space_left(prefix_len) == 0 { + self.estimate_size(block.span) + self.config.tab_width < self.space_left() + } else { + self.estimate_size(block.span) + prefix_len < self.space_left() + } + } else { + false + }; if can_inline_block { self.neverbreak(); self.print_block_inner( diff --git a/crates/fmt/testdata/DocComments/block.fmt.sol b/crates/fmt/testdata/DocComments/block.fmt.sol new file mode 100644 index 0000000000000..f216134747684 --- /dev/null +++ b/crates/fmt/testdata/DocComments/block.fmt.sol @@ -0,0 +1,117 @@ +// config: docs_style = "block" +pragma solidity ^0.8.13; + +/** + * @title A Hello world example + */ +contract HelloWorld { + /** + * Some example struct + */ + struct Person { + uint256 age; + address wallet; + } + + /** + * Here's a more double asterix comment + */ + Person public theDude; + + /** + * Will this long comment be wrapped leaving + * orphan words? + */ + Person public anotherDude; + + /** + * Constructs the dude + * @param age The dude's age + */ + constructor(uint256 age) { + theDude = Person({age: age, wallet: msg.sender}); + } + + /** + * @dev does nothing + */ + function example() public { + /** + * Does this add a whitespace error? + * + * Let's find out. + */ + } + + /** + * @dev Calculates a rectangle's surface and perimeter. + * @param w Width of the rectangle. + * @param h Height of the rectangle. + * @return s The calculated surface. + * @return p The calculated perimeter. + */ + function rectangle(uint256 w, uint256 h) + public + pure + returns (uint256 s, uint256 p) + { + s = w * h; + p = 2 * (w + h); + } + + /** + * A long doc line comment that will be wrapped + */ + function docLineOverflow() external {} + + function docLinePostfixOverflow() external {} + + /** + * A long doc line comment that will be wrapped + */ + + /** + * @notice Here is my comment + * - item 1 + * - item 2 + * Some equations: + * y = mx + b + */ + function anotherExample() external {} + + /** + * contract A { + * function foo() public { + * // does nothing. + * } + * } + */ + function multilineIndent() external {} + + /** + * contract A { + * function foo() public { + * // does nothing. + * } + * } + */ + function multilineMalformedIndent() external {} + + /** + * contract A { + * function withALongNameThatWillCauseCommentWrap() public { + * // does nothing. + * } + * } + */ + function malformedIndentOverflow() external {} +} + +/** + * contract A { + * function foo() public { + * // does nothing. + * } + * } + */ +function freeFloatingMultilineIndent() {} diff --git a/crates/fmt/testdata/DocComments/line.fmt.sol b/crates/fmt/testdata/DocComments/line.fmt.sol new file mode 100644 index 0000000000000..bf484db9e948d --- /dev/null +++ b/crates/fmt/testdata/DocComments/line.fmt.sol @@ -0,0 +1,87 @@ +// config: docs_style = "line" +pragma solidity ^0.8.13; + +/// @title A Hello world example +contract HelloWorld { + /// Some example struct + struct Person { + uint256 age; + address wallet; + } + + /// Here's a more double asterix comment + Person public theDude; + + /// Will this long comment be wrapped leaving + /// orphan words? + Person public anotherDude; + + /// Constructs the dude + /// @param age The dude's age + constructor(uint256 age) { + theDude = Person({age: age, wallet: msg.sender}); + } + + /// @dev does nothing + function example() public { + /// Does this add a whitespace error? + /// + /// Let's find out. + } + + /// @dev Calculates a rectangle's surface and perimeter. + /// @param w Width of the rectangle. + /// @param h Height of the rectangle. + /// @return s The calculated surface. + /// @return p The calculated perimeter. + function rectangle(uint256 w, uint256 h) + public + pure + returns (uint256 s, uint256 p) + { + s = w * h; + p = 2 * (w + h); + } + + /// A long doc line comment that will be wrapped + function docLineOverflow() external {} + + function docLinePostfixOverflow() external {} + + /// A long doc line comment that will be wrapped + + /// @notice Here is my comment + /// - item 1 + /// - item 2 + /// Some equations: + /// y = mx + b + function anotherExample() external {} + + /// contract A { + /// function foo() public { + /// // does nothing. + /// } + /// } + function multilineIndent() external {} + + /// contract A { + /// function foo() public { + /// // does nothing. + /// } + /// } + function multilineMalformedIndent() external {} + + /// contract A { + /// function withALongNameThatWillCauseCommentWrap() public { + /// // does nothing. + /// } + /// } + function malformedIndentOverflow() external {} +} + +/// contract A { +/// function foo() public { +/// // does nothing. +/// } +/// } +function freeFloatingMultilineIndent() {} diff --git a/crates/fmt/testdata/DocComments/wrap-comments.fmt.sol b/crates/fmt/testdata/DocComments/wrap-comments.fmt.sol index f8a45cbbe4115..d1ff4e9b1410c 100644 --- a/crates/fmt/testdata/DocComments/wrap-comments.fmt.sol +++ b/crates/fmt/testdata/DocComments/wrap-comments.fmt.sol @@ -1,6 +1,5 @@ // config: line_length = 40 // config: wrap_comments = true -// config: call_compact_args = false pragma solidity ^0.8.13; /// @title A Hello world example @@ -24,8 +23,7 @@ contract HelloWorld { /// @param age The dude's age constructor(uint256 age) { theDude = Person({ - age: age, - wallet: msg.sender + age: age, wallet: msg.sender }); } diff --git a/crates/fmt/testdata/EmitStatement/120.compact.fmt.sol b/crates/fmt/testdata/EmitStatement/120.compact.fmt.sol new file mode 100644 index 0000000000000..99b1446b894d8 --- /dev/null +++ b/crates/fmt/testdata/EmitStatement/120.compact.fmt.sol @@ -0,0 +1,48 @@ +// config: line_length = 120 +event NewEvent(address beneficiary, uint256 index, uint64 timestamp, uint64 endTimestamp); + +function emitEvent() { + emit NewEvent(beneficiary, _vestingBeneficiaries.length - 1, uint64(block.timestamp), endTimestamp); + + emit NewEvent( /* beneficiary */ + beneficiary, + /* index */ + _vestingBeneficiaries.length - 1, + /* timestamp */ + uint64(block.timestamp), + /* end timestamp */ + endTimestamp + ); + + emit NewEvent( + beneficiary, // beneficiary + _vestingBeneficiaries.length - 1, // index + uint64(block.timestamp), // timestamp + endTimestamp // end timestamp + ); + + // https://github.com/foundry-rs/foundry/issues/12029 + emit OperatorSharesDecreased( + defaultOperator, + address(0), + strategyMock, + depositAmount / 6 // 1 withdrawal not queued so decreased + ); + + // https://github.com/foundry-rs/foundry/issues/12146 + emit ISablierComptroller.DisableCustomFeeUSD( + protocol_protocol, caller_caller, user_users.sender, previousMinFeeUSD_0, newMinFeeUSD_feeUSD + ); + emit ISablierComptroller.DisableCustomFeeUSD({ + protocol: protocol, caller: caller, user: users.sender, previousMinFeeUSD: 0, newMinFeeUSD: feeUSD + }); + + emit ISablierLockupLinear.CreateLockupLinearStream({ + streamId: streamId, + commonParams: Lockup.CreateEventCommon({ + funder: msg.sender, sender: sender, recipient: recipient, depositAmount: depositAmount + }), + cliffTime: cliffTime, + unlockAmounts: unlockAmounts + }); +} diff --git a/crates/fmt/testdata/EmitStatement/120.fmt.sol b/crates/fmt/testdata/EmitStatement/120.fmt.sol index 927184651b0ba..8e12d544bacf9 100644 --- a/crates/fmt/testdata/EmitStatement/120.fmt.sol +++ b/crates/fmt/testdata/EmitStatement/120.fmt.sol @@ -1,4 +1,5 @@ // config: line_length = 120 +// config: prefer_compact = "none" event NewEvent(address beneficiary, uint256 index, uint64 timestamp, uint64 endTimestamp); function emitEvent() { @@ -30,9 +31,19 @@ function emitEvent() { ); // https://github.com/foundry-rs/foundry/issues/12146 - emit ISablierComptroller.DisableCustomFeeUSD(protocol, caller, users.sender, 0, feeUSD); + emit ISablierComptroller.DisableCustomFeeUSD( + protocol_protocol, + caller_caller, + user_users.sender, + previousMinFeeUSD_0, + newMinFeeUSD_feeUSD + ); emit ISablierComptroller.DisableCustomFeeUSD({ - protocol: protocol, caller: caller, user: users.sender, previousMinFeeUSD: 0, newMinFeeUSD: feeUSD + protocol: protocol, + caller: caller, + user: users.sender, + previousMinFeeUSD: 0, + newMinFeeUSD: feeUSD }); emit ISablierLockupLinear.CreateLockupLinearStream({ @@ -41,12 +52,7 @@ function emitEvent() { funder: msg.sender, sender: sender, recipient: recipient, - depositAmount: depositAmount, - token: token, - cancelable: cancelable, - transferable: transferable, - timestamps: timestamps, - shape: shape + depositAmount: depositAmount }), cliffTime: cliffTime, unlockAmounts: unlockAmounts diff --git a/crates/fmt/testdata/EmitStatement/fmt.sol b/crates/fmt/testdata/EmitStatement/fmt.sol index af351d6c06a3e..b31df04a7818e 100644 --- a/crates/fmt/testdata/EmitStatement/fmt.sol +++ b/crates/fmt/testdata/EmitStatement/fmt.sol @@ -38,7 +38,11 @@ function emitEvent() { // https://github.com/foundry-rs/foundry/issues/12146 emit ISablierComptroller.DisableCustomFeeUSD( - protocol, caller, users.sender, 0, feeUSD + protocol_protocol, + caller_caller, + user_users.sender, + previousMinFeeUSD_0, + newMinFeeUSD_feeUSD ); emit ISablierComptroller.DisableCustomFeeUSD({ protocol: protocol, @@ -54,12 +58,7 @@ function emitEvent() { funder: msg.sender, sender: sender, recipient: recipient, - depositAmount: depositAmount, - token: token, - cancelable: cancelable, - transferable: transferable, - timestamps: timestamps, - shape: shape + depositAmount: depositAmount }), cliffTime: cliffTime, unlockAmounts: unlockAmounts diff --git a/crates/fmt/testdata/EmitStatement/original.sol b/crates/fmt/testdata/EmitStatement/original.sol index 657126374d718..bb554fa974ebd 100644 --- a/crates/fmt/testdata/EmitStatement/original.sol +++ b/crates/fmt/testdata/EmitStatement/original.sol @@ -31,7 +31,7 @@ function emitEvent() { ); // https://github.com/foundry-rs/foundry/issues/12146 - emit ISablierComptroller.DisableCustomFeeUSD(protocol, caller, users.sender, 0, feeUSD); + emit ISablierComptroller.DisableCustomFeeUSD(protocol_protocol, caller_caller, user_users.sender, previousMinFeeUSD_0, newMinFeeUSD_feeUSD); emit ISablierComptroller.DisableCustomFeeUSD({ protocol: protocol, caller: caller, user: users.sender, previousMinFeeUSD: 0, newMinFeeUSD: feeUSD }); emit ISablierLockupLinear.CreateLockupLinearStream({ @@ -40,12 +40,7 @@ function emitEvent() { funder: msg.sender, sender: sender, recipient: recipient, - depositAmount: depositAmount, - token: token, - cancelable: cancelable, - transferable: transferable, - timestamps: timestamps, - shape: shape + depositAmount: depositAmount }), cliffTime: cliffTime, unlockAmounts: unlockAmounts diff --git a/crates/fmt/testdata/IfStatement2/120.fmt.sol b/crates/fmt/testdata/IfStatement2/120.fmt.sol index e5d36087fe410..beb31cec549b9 100644 --- a/crates/fmt/testdata/IfStatement2/120.fmt.sol +++ b/crates/fmt/testdata/IfStatement2/120.fmt.sol @@ -17,4 +17,12 @@ contract IfStatement { : Math.mulDiv(vaultUsdValue[i], 1e18, totalDepositedTvl, Math.Rounding.Floor); } } + + // https://github.com/foundry-rs/foundry/issues/12315 + function repro_longComplexExpr() { + vars.expectedSnapshotTime = withdrawAmount + <= getDescaledAmount(flow.getSnapshotDebtScaled(streamId), flow.getTokenDecimals(streamId)) + ? flow.getSnapshotTime(streamId) + : getBlockTimestamp(); + } } diff --git a/crates/fmt/testdata/IfStatement2/fmt.sol b/crates/fmt/testdata/IfStatement2/fmt.sol index 4553642128243..7dc3ce088bb5c 100644 --- a/crates/fmt/testdata/IfStatement2/fmt.sol +++ b/crates/fmt/testdata/IfStatement2/fmt.sol @@ -26,4 +26,15 @@ contract IfStatement { ); } } + + // https://github.com/foundry-rs/foundry/issues/12315 + function repro_longComplexExpr() { + vars.expectedSnapshotTime = withdrawAmount + <= getDescaledAmount( + flow.getSnapshotDebtScaled(streamId), + flow.getTokenDecimals(streamId) + ) + ? flow.getSnapshotTime(streamId) + : getBlockTimestamp(); + } } diff --git a/crates/fmt/testdata/IfStatement2/original.sol b/crates/fmt/testdata/IfStatement2/original.sol index 909320da01093..1dac9109a458f 100644 --- a/crates/fmt/testdata/IfStatement2/original.sol +++ b/crates/fmt/testdata/IfStatement2/original.sol @@ -18,4 +18,12 @@ contract IfStatement { : Math.mulDiv(vaultUsdValue[i], 1e18, totalDepositedTvl, Math.Rounding.Floor); } } + + // https://github.com/foundry-rs/foundry/issues/12315 + function repro_longComplexExpr() { + vars. expectedSnapshotTime = withdrawAmount + <= getDescaledAmount(flow.getSnapshotDebtScaled (streamId), flow.getTokenDecimals(streamId)) + ? flow.getSnapshotTime(streamId) + : getBlockTimestamp (); + } } diff --git a/crates/fmt/testdata/ImportDirective/bracket-spacing.fmt.sol b/crates/fmt/testdata/ImportDirective/bracket-spacing.fmt.sol index 5c5ae93e9a692..b0f4fd067d465 100644 --- a/crates/fmt/testdata/ImportDirective/bracket-spacing.fmt.sol +++ b/crates/fmt/testdata/ImportDirective/bracket-spacing.fmt.sol @@ -19,3 +19,8 @@ import { symbol3 as alias3, symbol4 } from "File2.sol"; + +// Single import that exceeds line length (121 chars) +import { + ITransparentUpgradeableProxy +} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; diff --git a/crates/fmt/testdata/ImportDirective/fmt.sol b/crates/fmt/testdata/ImportDirective/fmt.sol index 83a739f4e1e73..c4ce5f3166750 100644 --- a/crates/fmt/testdata/ImportDirective/fmt.sol +++ b/crates/fmt/testdata/ImportDirective/fmt.sol @@ -18,3 +18,8 @@ import { symbol3 as alias3, symbol4 } from "File2.sol"; + +// Single import that exceeds line length (121 chars) +import { + ITransparentUpgradeableProxy +} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; diff --git a/crates/fmt/testdata/ImportDirective/original.sol b/crates/fmt/testdata/ImportDirective/original.sol index f027174512196..2a18f88f0fa33 100644 --- a/crates/fmt/testdata/ImportDirective/original.sol +++ b/crates/fmt/testdata/ImportDirective/original.sol @@ -8,3 +8,6 @@ import {symbol1 as alias0, symbol2} from "File.sol"; import {symbol1 as alias0, symbol2} from 'File.sol'; import {symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4} from "File2.sol"; import {symbol1 as alias1, symbol2 as alias2, symbol3 as alias3, symbol4} from 'File2.sol'; + +// Single import that exceeds line length (121 chars) +import { ITransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; diff --git a/crates/fmt/testdata/ImportDirective/preserve-quote.fmt.sol b/crates/fmt/testdata/ImportDirective/preserve-quote.fmt.sol index 66d2a1d1ec6c1..c759965928ec2 100644 --- a/crates/fmt/testdata/ImportDirective/preserve-quote.fmt.sol +++ b/crates/fmt/testdata/ImportDirective/preserve-quote.fmt.sol @@ -19,3 +19,8 @@ import { symbol3 as alias3, symbol4 } from 'File2.sol'; + +// Single import that exceeds line length (121 chars) +import { + ITransparentUpgradeableProxy +} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; diff --git a/crates/fmt/testdata/ImportDirective/single-quote.fmt.sol b/crates/fmt/testdata/ImportDirective/single-quote.fmt.sol index d72e043f4f5d7..1820bd5166841 100644 --- a/crates/fmt/testdata/ImportDirective/single-quote.fmt.sol +++ b/crates/fmt/testdata/ImportDirective/single-quote.fmt.sol @@ -19,3 +19,8 @@ import { symbol3 as alias3, symbol4 } from 'File2.sol'; + +// Single import that exceeds line length (121 chars) +import { + ITransparentUpgradeableProxy +} from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; diff --git a/crates/fmt/testdata/ImportDirective/single_line_import.fmt.sol b/crates/fmt/testdata/ImportDirective/single_line_import.fmt.sol new file mode 100644 index 0000000000000..5644e336dbb97 --- /dev/null +++ b/crates/fmt/testdata/ImportDirective/single_line_import.fmt.sol @@ -0,0 +1,24 @@ +// config: single_line_imports = true +import "SomeFile.sol"; +import "SomeFile.sol"; +import "SomeFile.sol" as SomeOtherFile; +import "SomeFile.sol" as SomeOtherFile; +import "AnotherFile.sol" as SomeSymbol; +import "AnotherFile.sol" as SomeSymbol; +import {symbol1 as alias0, symbol2} from "File.sol"; +import {symbol1 as alias0, symbol2} from "File.sol"; +import { + symbol1 as alias1, + symbol2 as alias2, + symbol3 as alias3, + symbol4 +} from "File2.sol"; +import { + symbol1 as alias1, + symbol2 as alias2, + symbol3 as alias3, + symbol4 +} from "File2.sol"; + +// Single import that exceeds line length (121 chars) +import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; diff --git a/crates/fmt/testdata/NamedFunctionCallExpression/fmt.sol b/crates/fmt/testdata/NamedFunctionCallExpression/fmt.sol index 8b0690544c8b0..e8f832e3e299f 100644 --- a/crates/fmt/testdata/NamedFunctionCallExpression/fmt.sol +++ b/crates/fmt/testdata/NamedFunctionCallExpression/fmt.sol @@ -1,4 +1,4 @@ -// config: call_compact_args = false +// config: prefer_compact = "events_errors" contract NamedFunctionCallExpression { struct SimpleStruct { uint256 val; diff --git a/crates/fmt/testdata/OperatorExpressions/120.fmt.sol b/crates/fmt/testdata/OperatorExpressions/120.fmt.sol index d50d5f2ba9021..0a6d58cef8698 100644 --- a/crates/fmt/testdata/OperatorExpressions/120.fmt.sol +++ b/crates/fmt/testdata/OperatorExpressions/120.fmt.sol @@ -82,5 +82,8 @@ contract Repro { || chainId == LINEA || chainId == MODE || chainId == MORPH || chainId == OPTIMISM || chainId == POLYGON || chainId == SCROLL || chainId == SEI || chainId == SOPHON || chainId == SUPERSEED || chainId == SONIC || chainId == UNICHAIN || chainId == XDC || chainId == ZKSYNC; + + callsGas += (3 * FixedPointMathLib.divUp(paramsLength, 32)) + + FixedPointMathLib.mulDivUp(paramsLength, paramsLength, 524_288); } } diff --git a/crates/fmt/testdata/OperatorExpressions/fmt.sol b/crates/fmt/testdata/OperatorExpressions/fmt.sol index e7ebdf77d1747..c913b9859f066 100644 --- a/crates/fmt/testdata/OperatorExpressions/fmt.sol +++ b/crates/fmt/testdata/OperatorExpressions/fmt.sol @@ -98,5 +98,8 @@ contract Repro { || chainId == POLYGON || chainId == SCROLL || chainId == SEI || chainId == SOPHON || chainId == SUPERSEED || chainId == SONIC || chainId == UNICHAIN || chainId == XDC || chainId == ZKSYNC; + + callsGas += (3 * FixedPointMathLib.divUp(paramsLength, 32)) + + FixedPointMathLib.mulDivUp(paramsLength, paramsLength, 524_288); } } diff --git a/crates/fmt/testdata/OperatorExpressions/original.sol b/crates/fmt/testdata/OperatorExpressions/original.sol index 0b897c881c7ca..0de13f2149dd0 100644 --- a/crates/fmt/testdata/OperatorExpressions/original.sol +++ b/crates/fmt/testdata/OperatorExpressions/original.sol @@ -71,5 +71,7 @@ contract Repro { || chainId == MODE || chainId == MORPH || chainId == OPTIMISM || chainId == POLYGON || chainId == SCROLL || chainId == SEI || chainId == SOPHON || chainId == SUPERSEED || chainId == SONIC || chainId == UNICHAIN || chainId == XDC || chainId == ZKSYNC; + + callsGas += (3 * FixedPointMathLib.divUp(paramsLength, 32)) + FixedPointMathLib.mulDivUp(paramsLength, paramsLength, 524_288); } } diff --git a/crates/fmt/testdata/OperatorExpressions/pow-no-space.fmt.sol b/crates/fmt/testdata/OperatorExpressions/pow-no-space.fmt.sol index 81655935a1271..f03f3a382f3de 100644 --- a/crates/fmt/testdata/OperatorExpressions/pow-no-space.fmt.sol +++ b/crates/fmt/testdata/OperatorExpressions/pow-no-space.fmt.sol @@ -99,5 +99,8 @@ contract Repro { || chainId == POLYGON || chainId == SCROLL || chainId == SEI || chainId == SOPHON || chainId == SUPERSEED || chainId == SONIC || chainId == UNICHAIN || chainId == XDC || chainId == ZKSYNC; + + callsGas += (3 * FixedPointMathLib.divUp(paramsLength, 32)) + + FixedPointMathLib.mulDivUp(paramsLength, paramsLength, 524_288); } } diff --git a/crates/fmt/testdata/ReprosCalls/110.fmt.sol b/crates/fmt/testdata/ReprosCalls/110.fmt.sol index dafd0006151fd..47ba38b2fa656 100644 --- a/crates/fmt/testdata/ReprosCalls/110.fmt.sol +++ b/crates/fmt/testdata/ReprosCalls/110.fmt.sol @@ -1,5 +1,5 @@ // config: line_length = 110 -function test() public { +function repros() public { require( keccak256(abi.encodePacked("this is a long string")) == keccak256(abi.encodePacked("some other long string")), @@ -86,7 +86,7 @@ function returnLongBinaryOp() returns (bytes32) { ); } -contract Orchestrator { +contract Repros { function test() public { uint256 globalBuyAmount = Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount); @@ -145,4 +145,22 @@ contract Orchestrator { { a = 1; } + + // https://github.com/foundry-rs/foundry/issues/12324 + function test_longCallWithOpts() { + flow.withdraw{value: FLOW_MIN_FEE_WEI}({ + streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D + }); + flow.withdraw{ + value: FLOW_MIN_FEE_WEI /* cmnt */ + }({ + streamId: defaultStreamId, + to: users.eve, + /* cmnt */ + amount: WITHDRAW_AMOUNT_6D + }); + flow.withdraw{value: FLOW_MIN_FEE_WEI}({ // cmnt + streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D + }); + } } diff --git a/crates/fmt/testdata/ReprosCalls/120.fmt.sol b/crates/fmt/testdata/ReprosCalls/120.fmt.sol index 2676ada8ad0bc..7615c199ccc54 100644 --- a/crates/fmt/testdata/ReprosCalls/120.fmt.sol +++ b/crates/fmt/testdata/ReprosCalls/120.fmt.sol @@ -1,6 +1,6 @@ // config: line_length = 120 // config: bracket_spacing = true -function test() public { +function repros() public { require( keccak256(abi.encodePacked("this is a long string")) == keccak256(abi.encodePacked("some other long string")), "string mismatch" @@ -79,7 +79,7 @@ function returnLongBinaryOp() returns (bytes32) { bytes32(uint256(Feature.unwrap(feature)) << 128 | uint256(block.chainid) << 64 | uint256(Nonce.unwrap(nonce))); } -contract Orchestrator { +contract Repros { function test() public { uint256 globalBuyAmount = Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount); uint256 globalBuyAmount = Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount); @@ -131,4 +131,22 @@ contract Orchestrator { function test_ffi_fuzz_addLiquidity_defaultPool(IPoolManager.ModifyLiquidityParams memory paramSeed) public { a = 1; } + + // https://github.com/foundry-rs/foundry/issues/12324 + function test_longCallWithOpts() { + flow.withdraw{ value: FLOW_MIN_FEE_WEI }({ + streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D + }); + flow.withdraw{ + value: FLOW_MIN_FEE_WEI /* cmnt */ + }({ + streamId: defaultStreamId, + to: users.eve, + /* cmnt */ + amount: WITHDRAW_AMOUNT_6D + }); + flow.withdraw{ value: FLOW_MIN_FEE_WEI }({ // cmnt + streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D + }); + } } diff --git a/crates/fmt/testdata/ReprosCalls/80.fmt.sol b/crates/fmt/testdata/ReprosCalls/80.fmt.sol index 2211e49eea2cc..47b8e1644d9ad 100644 --- a/crates/fmt/testdata/ReprosCalls/80.fmt.sol +++ b/crates/fmt/testdata/ReprosCalls/80.fmt.sol @@ -1,5 +1,5 @@ // config: line_length = 80 -function test() public { +function repros() public { require( keccak256(abi.encodePacked("this is a long string")) == keccak256(abi.encodePacked("some other long string")), @@ -119,7 +119,7 @@ function returnLongBinaryOp() returns (bytes32) { ); } -contract Orchestrator { +contract Repros { function test() public { uint256 globalBuyAmount = Take.take( state, @@ -205,4 +205,22 @@ contract Orchestrator { ) public { a = 1; } + + // https://github.com/foundry-rs/foundry/issues/12324 + function test_longCallWithOpts() { + flow.withdraw{value: FLOW_MIN_FEE_WEI}({ + streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D + }); + flow.withdraw{ + value: FLOW_MIN_FEE_WEI /* cmnt */ + }({ + streamId: defaultStreamId, + to: users.eve, + /* cmnt */ + amount: WITHDRAW_AMOUNT_6D + }); + flow.withdraw{value: FLOW_MIN_FEE_WEI}({ // cmnt + streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D + }); + } } diff --git a/crates/fmt/testdata/ReprosCalls/consistent.120.fmt.sol b/crates/fmt/testdata/ReprosCalls/consistent.120.fmt.sol new file mode 100644 index 0000000000000..a51f55ab6b440 --- /dev/null +++ b/crates/fmt/testdata/ReprosCalls/consistent.120.fmt.sol @@ -0,0 +1,165 @@ +// config: line_length = 120 +// config: bracket_spacing = true +// config: prefer_compact = "none" +function repros() public { + require( + keccak256(abi.encodePacked("this is a long string")) == keccak256(abi.encodePacked("some other long string")), + "string mismatch" + ); + + address lerp = LerpFactoryLike(lerpFab()).newLerp(_name, _target, _what, _startTime, _start, _end, _duration); + + (oracleRouter, eVault) = + execute(oracleRouterFactory, deployRouterForOracle, eVaultFactory, upgradable, asset, oracle, unitOfAccount); + + if (eVault == address(0)) { + eVault = address( + GenericFactory(eVaultFactory).createProxy(address(0), true, abi.encodePacked(asset, address(0), address(0))) + ); + } + + content = string.concat( + "{\"description\": \"", + description, + "\", \"name\": \"0x Settler feature ", + ItoA.itoa(Feature.unwrap(feature)), + "\"}\n" + ); + + oracleInfo = + abi.encode(LidoOracleInfo({ base: IOracle(oracleAddress).WSTETH(), quote: IOracle(oracleAddress).STETH() })); + + return someFunction().getValue().modifyValue().negate().scaleBySomeFactor(1000).transformToTuple(); + + SnapshotRegistry(adapterRegistry) + .add(adapter, LidoFundamentalOracle(adapter).WSTETH(), LidoFundamentalOracle(adapter).WETH()); + + (bool success, bytes memory data) = GenericFactory(eVaultFactory).implementation() + .staticcall(abi.encodePacked(EVCUtil.EVC.selector, uint256(0), uint256(0))); + + IEVC.BatchItem[] memory items = new IEVC.BatchItem[](3); + + items[0] = IEVC.BatchItem({ + onBehalfOfAccount: user, + targetContract: address(eGRT), + value: 0, + data: abi.encodeCall(IERC4626.withdraw, (1500e18, address(swapper), user)) + }); + items[1] = IEVC.BatchItem({ + onBehalfOfAccount: user, + targetContract: address(swapper), + value: 0, + data: abi.encodeCall(Swapper.multicall, multicallItems) + }); + items[2] = IEVC.BatchItem({ + onBehalfOfAccount: user, + targetContract: address(swapVerifier), + value: 0, + data: abi.encodeCall(swapVerifier.verifyDebtMax, (address(eSTETH), user, exactOutTolerance, type(uint256).max)) + }); + + uint256 fork = vm.createSelectFork("arbitrum", bytes32(0xdeadc0ffeedeadbeef)); + + ConstructorVictim victim = new ConstructorVictim(sender, "msg.sender", "not set during prank"); + + vm._expectCheatcodeRevert("short msg doesn't break"); + vm._expectCheatcodeRevert("failed parsing as `uint256`: missing hex prefix for hex string"); + vm.thisIsJustAReallyLongMemberWithoutAcall.LetsSeeHowItBreaks.willItBreakAsIntendedOrNot; + + bytes4[] memory targets = new bytes4[](0); + targets[0] = FuzzArtifactSelector("TargetArtifactSelectors.t.sol:Hi", selectors); + + emit IERC712View.Transfer(Create3.predict(_salt, address(_deployer)), address(o), id); + + return _verifyDeploymentRootHash(_getMerkleRoot(proof, hash), originalOwner) + .ternary(IERC1271.isValidSignature.selector, bytes4(0xffffffff)); +} + +function returnLongBinaryOp() returns (bytes32) { + return + bytes32(uint256(Feature.unwrap(feature)) << 128 | uint256(block.chainid) << 64 | uint256(Nonce.unwrap(nonce))); +} + +contract Repros { + function test() public { + uint256 globalBuyAmount = Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount); + uint256 globalBuyAmount = Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount); + + { + u.executionData = _transferExecution(address(paymentToken), address(0xabcd), 1 ether); + u.executionData = _transferExecution(address(paymentToken), address(0xabcd), 1 ether); + } + + ISettlerBase.AllowedSlippage memory allowedSlippage = ISettlerBase.AllowedSlippage({ + recipient: payable(address(0)), + buyToken: IERC20(address(0)), + minAmountOut: 0 + }); + ISettlerBase.AllowedSlippage memory allowedSlippage = ISettlerBase.AllowedSlippage({ + recipient: payable(address(0)), + buyToken: IERC20(address(0)), + minAmountOut: 0 + }); + + ISignatureTransfer.PermitTransferFrom memory permit = defaultERC20PermitTransfer( + address(fromToken()), + amount(), + 0 /* nonce */ + ); + ISignatureTransfer.PermitTransferFrom memory permit = defaultERC20PermitTransfer( + address(fromToken()), + amount(), + 0 /* nonce */ + ); + + // https://github.com/foundry-rs/foundry/issues/11834 + CurrenciesOutOfOrderOrEqual.selector.revertWith(Currency.unwrap(key.currency0), Currency.unwrap(key.currency1)); + + nestedStruct.withCalls.thatCause + .aBreak( + param1, + param2, + param3 // long line + ); + + // https://github.com/foundry-rs/foundry/issues/11835 + feeGrowthInside0X128 = self.feeGrowthGlobal0X128 - lower.feeGrowthOutside0X128 - upper.feeGrowthOutside0X128; + feeGrowthInside0X128 = self.feeGrowthGlobal0X128 - lower.feeGrowthOutside0X128 - upper.feeGrowthOutside0X128; + + // https://github.com/foundry-rs/foundry/issues/11875 + lpTail = LpPosition({ + tickLower: posTickLower, + tickUpper: posTickUpper, + liquidity: lpTailLiquidity, + id: uint16(id) + }); + } + + // https://github.com/foundry-rs/foundry/issues/11834 + function test_ffi_fuzz_addLiquidity_defaultPool(IPoolManager.ModifyLiquidityParams memory paramSeed) public { + a = 1; + } + + // https://github.com/foundry-rs/foundry/issues/12324 + function test_longCallWithOpts() { + flow.withdraw{ value: FLOW_MIN_FEE_WEI }({ + streamId: defaultStreamId, + to: users.eve, + amount: WITHDRAW_AMOUNT_6D + }); + flow.withdraw{ + value: FLOW_MIN_FEE_WEI /* cmnt */ + }({ + streamId: defaultStreamId, + to: users.eve, + /* cmnt */ + amount: WITHDRAW_AMOUNT_6D + }); + flow.withdraw{ value: FLOW_MIN_FEE_WEI }({ + // cmnt + streamId: defaultStreamId, + to: users.eve, + amount: WITHDRAW_AMOUNT_6D + }); + } +} diff --git a/crates/fmt/testdata/ReprosCalls/original.sol b/crates/fmt/testdata/ReprosCalls/original.sol index 53a3e5c5df80e..cb92b2a0c5b13 100644 --- a/crates/fmt/testdata/ReprosCalls/original.sol +++ b/crates/fmt/testdata/ReprosCalls/original.sol @@ -1,4 +1,4 @@ -function test() public { +function repros() public { require( keccak256(abi.encodePacked("this is a long string")) == keccak256(abi.encodePacked("some other long string")), "string mismatch" @@ -81,7 +81,7 @@ function returnLongBinaryOp() returns (bytes32) { bytes32(uint256(Feature.unwrap(feature)) << 128 | uint256(block.chainid) << 64 | uint256(Nonce.unwrap(nonce))); } -contract Orchestrator { +contract Repros { function test() public { uint256 globalBuyAmount = Take.take(state, notes, uint32(IPoolManager.take.selector), recipient, minBuyAmount); @@ -137,4 +137,12 @@ contract Orchestrator { ) public { a = 1; } + + // https://github.com/foundry-rs/foundry/issues/12324 + function test_longCallWithOpts() { + flow.withdraw{ value: FLOW_MIN_FEE_WEI }({streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D }); + flow.withdraw{ value: FLOW_MIN_FEE_WEI /* cmnt */ }({ streamId: defaultStreamId, to: users.eve, /* cmnt */ amount: WITHDRAW_AMOUNT_6D }); + flow.withdraw{ value: FLOW_MIN_FEE_WEI }({ // cmnt + streamId: defaultStreamId, to: users.eve, amount: WITHDRAW_AMOUNT_6D }); + } } diff --git a/crates/fmt/testdata/ReprosFunctionDefs/all.120.fmt.sol b/crates/fmt/testdata/ReprosFunctionDefs/all.120.fmt.sol index c1ac1c0e42c1f..ef580620d8486 100644 --- a/crates/fmt/testdata/ReprosFunctionDefs/all.120.fmt.sol +++ b/crates/fmt/testdata/ReprosFunctionDefs/all.120.fmt.sol @@ -2,6 +2,8 @@ // config: multiline_func_header = "all" contract Repros { // https://github.com/foundry-rs/foundry/issues/12109 + function createDefaultStream(UD21x18 ratePerSecond, uint40 startTime, IERC20 token_) internal returns (uint256); + function calculateStreamedPercentage( uint128 streamedAmount, uint128 depositedAmount diff --git a/crates/fmt/testdata/ReprosFunctionDefs/original.sol b/crates/fmt/testdata/ReprosFunctionDefs/original.sol index c757d03a05900..19c97e95f0c6c 100644 --- a/crates/fmt/testdata/ReprosFunctionDefs/original.sol +++ b/crates/fmt/testdata/ReprosFunctionDefs/original.sol @@ -1,4 +1,5 @@ contract Repros { // https://github.com/foundry-rs/foundry/issues/12109 + function createDefaultStream(UD21x18 ratePerSecond, uint40 startTime, IERC20 token_) internal returns (uint256); function calculateStreamedPercentage(uint128 streamedAmount, uint128 depositedAmount) internal pure returns (uint256) { a = 1; } } diff --git a/crates/fmt/testdata/RevertNamedArgsStatement/bracket-spacing.fmt.sol b/crates/fmt/testdata/RevertNamedArgsStatement/bracket-spacing.fmt.sol index e5161a1ee7d08..0ba90b1060973 100644 --- a/crates/fmt/testdata/RevertNamedArgsStatement/bracket-spacing.fmt.sol +++ b/crates/fmt/testdata/RevertNamedArgsStatement/bracket-spacing.fmt.sol @@ -1,4 +1,4 @@ -// config: call_compact_args = false +// config: prefer_compact = "events_errors" // config: bracket_spacing = true contract RevertNamedArgsStatement { error EmptyError(); diff --git a/crates/fmt/testdata/RevertNamedArgsStatement/fmt.sol b/crates/fmt/testdata/RevertNamedArgsStatement/fmt.sol index ddb9228dfdc30..11c8069fe521c 100644 --- a/crates/fmt/testdata/RevertNamedArgsStatement/fmt.sol +++ b/crates/fmt/testdata/RevertNamedArgsStatement/fmt.sol @@ -1,4 +1,4 @@ -// config: call_compact_args = false +// config: prefer_compact = "events_errors" contract RevertNamedArgsStatement { error EmptyError(); error SimpleError(uint256 val); diff --git a/crates/fmt/testdata/RevertStatement/fmt.sol b/crates/fmt/testdata/RevertStatement/fmt.sol index 9f52fbceba927..4ed9eb348d39d 100644 --- a/crates/fmt/testdata/RevertStatement/fmt.sol +++ b/crates/fmt/testdata/RevertStatement/fmt.sol @@ -1,3 +1,4 @@ +// config: prefer_compact = "none" contract RevertStatement { error TestError(uint256, bool, string); @@ -42,11 +43,15 @@ contract RevertStatement { revert TestError(0, false, message); revert TestError( - 0, false, someVeryLongFunctionNameToGetDynamicErrorMessageString() + 0, + false, + someVeryLongFunctionNameToGetDynamicErrorMessageString() ); revert /* comment13 */ /* comment14 */ TestError( /* comment15 */ - 1234567890, false, message + 1234567890, + false, + message ); revert TestError( /* comment16 */ diff --git a/crates/fmt/testdata/SimpleComments/fmt.sol b/crates/fmt/testdata/SimpleComments/fmt.sol index e9f399968e36d..1520db43d4162 100644 --- a/crates/fmt/testdata/SimpleComments/fmt.sol +++ b/crates/fmt/testdata/SimpleComments/fmt.sol @@ -1,4 +1,8 @@ contract SimpleComments { + uint40 constant PERIOD = uint40(12345); // ~578 days + // Represents the depletion timestamp + uint40 constant WARP_PERIOD = FEB_1_2025 + PERIOD; + //´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*: // VARIABLES //.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.• diff --git a/crates/fmt/testdata/SimpleComments/original.sol b/crates/fmt/testdata/SimpleComments/original.sol index 2dff78dce6a3c..7020527b43671 100644 --- a/crates/fmt/testdata/SimpleComments/original.sol +++ b/crates/fmt/testdata/SimpleComments/original.sol @@ -1,4 +1,8 @@ contract SimpleComments { + uint40 constant PERIOD = uint40(12345); // ~578 days + // Represents the depletion timestamp + uint40 constant WARP_PERIOD = FEB_1_2025 + PERIOD; + //´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*: // VARIABLES //.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.• diff --git a/crates/fmt/testdata/SimpleComments/wrap-comments.fmt.sol b/crates/fmt/testdata/SimpleComments/wrap-comments.fmt.sol index 7e30f8e9d507b..d41b8efa99f08 100644 --- a/crates/fmt/testdata/SimpleComments/wrap-comments.fmt.sol +++ b/crates/fmt/testdata/SimpleComments/wrap-comments.fmt.sol @@ -1,6 +1,10 @@ // config: line_length = 60 // config: wrap_comments = true contract SimpleComments { + uint40 constant PERIOD = uint40(12345); // ~578 days + // Represents the depletion timestamp + uint40 constant WARP_PERIOD = FEB_1_2025 + PERIOD; + //´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*: // VARIABLES //.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.• @@ -46,8 +50,8 @@ contract SimpleComments { function test4() public view returns (uint256) { uint256 abc; // long postfix comment that exceeds - // line width. the comment should be split and - // carried over to the next line + // line width. the comment should be split and + // carried over to the next line uint256 abc2; // reallylongsinglewordcommentthatexceedslinewidththecommentshouldbesplitandcarriedovertothenextline // long prefix comment that exceeds line width. the diff --git a/crates/fmt/testdata/TryStatement/fmt.sol b/crates/fmt/testdata/TryStatement/fmt.sol index 9d48d66f5063d..cff134e646038 100644 --- a/crates/fmt/testdata/TryStatement/fmt.sol +++ b/crates/fmt/testdata/TryStatement/fmt.sol @@ -99,6 +99,6 @@ contract TryStatement { uint80, int256 _price, uint256, uint256 _updatedAt, uint80 ) { return true; - } catch {} + } catch {} // https://github.com/foundry-rs/foundry/issues/12240 } } diff --git a/crates/fmt/testdata/TryStatement/original.sol b/crates/fmt/testdata/TryStatement/original.sol index fe50355ecb4fc..288ad81293738 100644 --- a/crates/fmt/testdata/TryStatement/original.sol +++ b/crates/fmt/testdata/TryStatement/original.sol @@ -89,6 +89,6 @@ contract TryStatement { function try_reallyLongCall() { try AggregatorV3Interface(oracle).latestRoundData() returns (uint80, int256 _price, uint256, uint256 _updatedAt, uint80) { return true; - } catch {} + } catch {} // https://github.com/foundry-rs/foundry/issues/12240 } } diff --git a/crates/fmt/testdata/VariableAssignment/bracket-spacing.fmt.sol b/crates/fmt/testdata/VariableAssignment/bracket-spacing.fmt.sol index 2bf3415bcce22..07b4866e4d6cb 100644 --- a/crates/fmt/testdata/VariableAssignment/bracket-spacing.fmt.sol +++ b/crates/fmt/testdata/VariableAssignment/bracket-spacing.fmt.sol @@ -38,4 +38,35 @@ contract TestContract { "0x0000000000000000000000000000000000000000000000000000000000000000," "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; } + + // https://github.com/foundry-rs/foundry/issues/12254 + function test_longIndexedCall() { + bytes memory message = mailboxes[destinationDomain].buildMessage( + originDomain, + bytes32(0), + address(inbox).toBytes32(), + abi.encode(orderId, bytes32(0), address(0)) + ); + // should have identicall behavior when call of the same size without indexing + bytes memory message = mailboxes_destinationDomains.buildMessage( + originDomain, + bytes32(0), + address(inbox).toBytes32(), + abi.encode(orderId, bytes32(0), address(0)) + ); + } + + // https://github.com/foundry-rs/foundry/issues/12322 + function test_longComplexBinExpr() { + vars.previousTotalDebt = getDescaledAmount( + flow.getSnapshotDebtScaled(streamId), + flow.getTokenDecimals(streamId) + ) + vars.previousOngoingDebtScaled; + + vars.previousTotalDebt = vars.reallyLongVarThatCausesALineBreak + + vars.previousOngoingDebtScaled; + + vars.previousTotalDebt = vars.reallyLongVarThatCausesALineBreak() + .previousOngoingDebtScaled(); + } } diff --git a/crates/fmt/testdata/VariableAssignment/fmt.sol b/crates/fmt/testdata/VariableAssignment/fmt.sol index f77ca77545552..080992fe050b0 100644 --- a/crates/fmt/testdata/VariableAssignment/fmt.sol +++ b/crates/fmt/testdata/VariableAssignment/fmt.sol @@ -37,4 +37,35 @@ contract TestContract { "0x0000000000000000000000000000000000000000000000000000000000000000," "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; } + + // https://github.com/foundry-rs/foundry/issues/12254 + function test_longIndexedCall() { + bytes memory message = mailboxes[destinationDomain].buildMessage( + originDomain, + bytes32(0), + address(inbox).toBytes32(), + abi.encode(orderId, bytes32(0), address(0)) + ); + // should have identicall behavior when call of the same size without indexing + bytes memory message = mailboxes_destinationDomains.buildMessage( + originDomain, + bytes32(0), + address(inbox).toBytes32(), + abi.encode(orderId, bytes32(0), address(0)) + ); + } + + // https://github.com/foundry-rs/foundry/issues/12322 + function test_longComplexBinExpr() { + vars.previousTotalDebt = getDescaledAmount( + flow.getSnapshotDebtScaled(streamId), + flow.getTokenDecimals(streamId) + ) + vars.previousOngoingDebtScaled; + + vars.previousTotalDebt = vars.reallyLongVarThatCausesALineBreak + + vars.previousOngoingDebtScaled; + + vars.previousTotalDebt = vars.reallyLongVarThatCausesALineBreak() + .previousOngoingDebtScaled(); + } } diff --git a/crates/fmt/testdata/VariableAssignment/original.sol b/crates/fmt/testdata/VariableAssignment/original.sol index 8f79a5b06dc3f..2ccc26c97df29 100644 --- a/crates/fmt/testdata/VariableAssignment/original.sol +++ b/crates/fmt/testdata/VariableAssignment/original.sol @@ -36,4 +36,20 @@ contract TestContract { "0x0000000000000000000000000000000000000000000000000000000000000000," "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; } + + // https://github.com/foundry-rs/foundry/issues/12254 + function test_longIndexedCall() { + bytes memory message = mailboxes[destinationDomain].buildMessage(originDomain, bytes32(0), address(inbox).toBytes32(), abi.encode(orderId, bytes32(0), address(0))); + // should have identicall behavior when call of the same size without indexing + bytes memory message = mailboxes_destinationDomains.buildMessage(originDomain, bytes32(0), address(inbox).toBytes32(), abi.encode(orderId, bytes32(0), address(0))); + } + + // https://github.com/foundry-rs/foundry/issues/12322 + function test_longComplexBinExpr() { + vars.previousTotalDebt = getDescaledAmount(flow.getSnapshotDebtScaled(streamId), flow.getTokenDecimals(streamId)) + vars.previousOngoingDebtScaled; + + vars.previousTotalDebt = vars.reallyLongVarThatCausesALineBreak + vars.previousOngoingDebtScaled; + + vars.previousTotalDebt = vars.reallyLongVarThatCausesALineBreak() .previousOngoingDebtScaled(); + } } diff --git a/crates/fmt/testdata/Yul/fmt.sol b/crates/fmt/testdata/Yul/fmt.sol index 3db955e48ea69..26ae8f2eb884d 100644 --- a/crates/fmt/testdata/Yul/fmt.sol +++ b/crates/fmt/testdata/Yul/fmt.sol @@ -228,7 +228,28 @@ contract Yul { result, p := parseValue(input, 0, p, e) mstore8(e, c) // Restore the original char at the end. } - if or(lt(p, e), iszero(result)) { fail() } + } + } + + assembly { + function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut { + _pOut := pIn_ + if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'. + if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'. + let c_ := chr(_pOut) + _pOut := add(_pOut, 1) + if iszero(eq(c_, 48)) { + _pOut := skip0To9s(_pOut, end_, 0) + } // Not '0'. + if eq(chr(_pOut), 46) { + _pOut := skip0To9s(add(_pOut, 1), end_, 1) + } // '.'. + let t_ := mload(_pOut) + if eq(or(0x20, byte(0, t_)), 101) { + // forgefmt: disable-next-item + _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'. + add(_pOut, 1)), end_, 1) + } } } } diff --git a/crates/fmt/testdata/Yul/original.sol b/crates/fmt/testdata/Yul/original.sol index 11347d492e911..1fba402759726 100644 --- a/crates/fmt/testdata/Yul/original.sol +++ b/crates/fmt/testdata/Yul/original.sol @@ -171,7 +171,24 @@ contract Yul { result, p := parseValue(input, 0, p, e) mstore8(e, c) // Restore the original char at the end. } - if or(lt(p, e), iszero(result)) { fail() } + } + } + + assembly { + function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut { + _pOut := pIn_ + if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'. + if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'. + let c_ := chr(_pOut) + _pOut := add(_pOut, 1) + if iszero(eq(c_, 48)) { _pOut := skip0To9s(_pOut, end_, 0) } // Not '0'. + if eq(chr(_pOut), 46) { _pOut := skip0To9s(add(_pOut, 1), end_, 1) } // '.'. + let t_ := mload(_pOut) + if eq(or(0x20, byte(0, t_)), 101) { + // forgefmt: disable-next-item + _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'. + add(_pOut, 1)), end_, 1) + } } } } diff --git a/crates/forge/tests/cli/config.rs b/crates/forge/tests/cli/config.rs index 991effdef5f95..e2778eb8d73c0 100644 --- a/crates/forge/tests/cli/config.rs +++ b/crates/forge/tests/cli/config.rs @@ -132,11 +132,13 @@ hex_underscore = "remove" single_line_statement_blocks = "preserve" override_spacing = false wrap_comments = false +docs_style = "preserve" ignore = [] contract_new_lines = false sort_imports = false pow_no_space = false -call_compact_args = true +prefer_compact = "all" +single_line_imports = false [lint] severity = [] @@ -1306,11 +1308,13 @@ forgetest_init!(test_default_config, |prj, cmd| { "single_line_statement_blocks": "preserve", "override_spacing": false, "wrap_comments": false, + "docs_style": "preserve", "ignore": [], "contract_new_lines": false, "sort_imports": false, "pow_no_space": false, - "call_compact_args": true + "prefer_compact": "all", + "single_line_imports": false }, "lint": { "severity": [], diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index 9fc502f47eac1..77a54c778e907 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -3260,3 +3260,45 @@ ONCHAIN EXECUTION COMPLETE & SUCCESSFUL. "#]]); }); + +// +forgetest_async!(can_execute_script_with_createx_and_via_ir, |prj, cmd| { + foundry_test_utils::util::initialize(prj.root()); + prj.update_config(|config| { + config.optimizer = Some(true); + config.via_ir = true; + }); + prj.add_script("CreateXScript.s.sol", include_str!("../fixtures/CreateXScript.sol")); + + let (_api, handle) = spawn(NodeConfig::test().with_auto_impersonate(true)).await; + cmd.cast_fuse() + .args([ + "send", + "0xeD456e05CaAb11d66C4c797dD6c1D6f9A7F352b5", + "--value", + "1000000000000000000", + "--from", + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "--unlocked", + "--rpc-url", + &handle.http_endpoint(), + ]) + .assert_success(); + cmd.cast_fuse() + .args(["publish", "0xf92f698085174876e800832dc6c08080b92f1660a06040523060805234801561001457600080fd5b50608051612e3e6100d860003960008181610603015281816107050152818161082b015281816108d50152818161127f01528181611375015281816113e00152818161141f015281816114a7015281816115b3015281816117d20152818161183d0152818161187c0152818161190401528181611ac501528181611c7801528181611ce301528181611d2201528181611daa01528181611fe901528181612206015281816122f20152818161244d015281816124a601526125820152612e3e6000f3fe60806040526004361061018a5760003560e01c806381503da1116100d6578063d323826a1161007f578063e96deee411610059578063e96deee414610395578063f5745aba146103a8578063f9664498146103bb57600080fd5b8063d323826a1461034f578063ddda0acb1461036f578063e437252a1461038257600080fd5b80639c36a286116100b05780639c36a28614610316578063a7db93f214610329578063c3fe107b1461033c57600080fd5b806381503da1146102d0578063890c283b146102e357806398e810771461030357600080fd5b80632f990e3f116101385780636cec2536116101125780636cec25361461027d57806374637a7a1461029d5780637f565360146102bd57600080fd5b80632f990e3f1461023757806331a7c8c81461024a57806342d654fc1461025d57600080fd5b806327fe18221161016957806327fe1822146101f15780632852527a1461020457806328ddd0461461021757600080fd5b8062d84acb1461018f57806326307668146101cb57806326a32fc7146101de575b600080fd5b6101a261019d366004612915565b6103ce565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6101a26101d9366004612994565b6103e6565b6101a26101ec3660046129db565b610452565b6101a26101ff3660046129db565b6104de565b6101a2610212366004612a39565b610539565b34801561022357600080fd5b506101a2610232366004612a90565b6106fe565b6101a2610245366004612aa9565b61072a565b6101a2610258366004612aa9565b6107bb565b34801561026957600080fd5b506101a2610278366004612b1e565b6107c9565b34801561028957600080fd5b506101a2610298366004612a90565b610823565b3480156102a957600080fd5b506101a26102b8366004612b4a565b61084f565b6101a26102cb3660046129db565b611162565b6101a26102de366004612b74565b6111e8565b3480156102ef57600080fd5b506101a26102fe366004612bac565b611276565b6101a2610311366004612bce565b6112a3565b6101a2610324366004612994565b611505565b6101a2610337366004612c49565b6116f1565b6101a261034a366004612aa9565b611964565b34801561035b57600080fd5b506101a261036a366004612cd9565b6119ed565b6101a261037d366004612c49565b611a17565b6101a2610390366004612bce565b611e0c565b6101a26103a3366004612915565b611e95565b6101a26103b6366004612bce565b611ea4565b6101a26103c9366004612b74565b611f2d565b60006103dd8585858533611a17565b95945050505050565b6000806103f2846120db565b90508083516020850134f59150610408826123d3565b604051819073ffffffffffffffffffffffffffffffffffffffff8416907fb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f790600090a35092915050565b60006104d86104d260408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b836103e6565b92915050565b600081516020830134f090506104f3816123d3565b60405173ffffffffffffffffffffffffffffffffffffffff8216907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a2919050565b600080610545856120db565b905060008460601b90506040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528160148201527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006028820152826037826000f593505073ffffffffffffffffffffffffffffffffffffffff8316610635576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660048201526024015b60405180910390fd5b604051829073ffffffffffffffffffffffffffffffffffffffff8516907fb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f790600090a36000808473ffffffffffffffffffffffffffffffffffffffff1634876040516106a19190612d29565b60006040518083038185875af1925050503d80600081146106de576040519150601f19603f3d011682016040523d82523d6000602084013e6106e3565b606091505b50915091506106f382828961247d565b505050509392505050565b60006104d87f00000000000000000000000000000000000000000000000000000000000000008361084f565b60006107b36107aa60408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b85858533611a17565b949350505050565b60006107b3848484336112a3565b60006040518260005260ff600b53836020527f21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f6040526055600b20601452806040525061d694600052600160345350506017601e20919050565b60006104d8827f00000000000000000000000000000000000000000000000000000000000000006107c9565b600060607f9400000000000000000000000000000000000000000000000000000000000000610887600167ffffffffffffffff612d45565b67ffffffffffffffff16841115610902576040517f3c55ab3b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b836000036109c7576040517fd60000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f800000000000000000000000000000000000000000000000000000000000000060368201526037015b6040516020818303038152906040529150611152565b607f8411610a60576040517fd60000000000000000000000000000000000000000000000000000000000000060208201527fff0000000000000000000000000000000000000000000000000000000000000080831660218301527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16602283015260f886901b1660368201526037016109b1565b60ff8411610b1f576040517fd70000000000000000000000000000000000000000000000000000000000000060208201527fff0000000000000000000000000000000000000000000000000000000000000080831660218301527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b1660228301527f8100000000000000000000000000000000000000000000000000000000000000603683015260f886901b1660378201526038016109b1565b61ffff8411610bff576040517fd80000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f820000000000000000000000000000000000000000000000000000000000000060368201527fffff00000000000000000000000000000000000000000000000000000000000060f086901b1660378201526039016109b1565b62ffffff8411610ce0576040517fd90000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f830000000000000000000000000000000000000000000000000000000000000060368201527fffffff000000000000000000000000000000000000000000000000000000000060e886901b166037820152603a016109b1565b63ffffffff8411610dc2576040517fda0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f840000000000000000000000000000000000000000000000000000000000000060368201527fffffffff0000000000000000000000000000000000000000000000000000000060e086901b166037820152603b016109b1565b64ffffffffff8411610ea5576040517fdb0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f850000000000000000000000000000000000000000000000000000000000000060368201527fffffffffff00000000000000000000000000000000000000000000000000000060d886901b166037820152603c016109b1565b65ffffffffffff8411610f89576040517fdc0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f860000000000000000000000000000000000000000000000000000000000000060368201527fffffffffffff000000000000000000000000000000000000000000000000000060d086901b166037820152603d016109b1565b66ffffffffffffff841161106e576040517fdd0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f870000000000000000000000000000000000000000000000000000000000000060368201527fffffffffffffff0000000000000000000000000000000000000000000000000060c886901b166037820152603e016109b1565b6040517fde0000000000000000000000000000000000000000000000000000000000000060208201527fff00000000000000000000000000000000000000000000000000000000000000821660218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b1660228201527f880000000000000000000000000000000000000000000000000000000000000060368201527fffffffffffffffff00000000000000000000000000000000000000000000000060c086901b166037820152603f0160405160208183030381529060405291505b5080516020909101209392505050565b60006104d86111e260408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b83611505565b600061126f61126860408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b8484610539565b9392505050565b600061126f83837f00000000000000000000000000000000000000000000000000000000000000006119ed565b60008451602086018451f090506112b9816123d3565b60405173ffffffffffffffffffffffffffffffffffffffff8216907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a26000808273ffffffffffffffffffffffffffffffffffffffff168560200151876040516113279190612d29565b60006040518083038185875af1925050503d8060008114611364576040519150601f19603f3d011682016040523d82523d6000602084013e611369565b606091505b5091509150816113c9577f0000000000000000000000000000000000000000000000000000000000000000816040517fa57ca23900000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001631156114fb578373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163160405160006040518083038185875af1925050503d8060008114611495576040519150601f19603f3d011682016040523d82523d6000602084013e61149a565b606091505b509092509050816114fb577f0000000000000000000000000000000000000000000000000000000000000000816040517fc2b3f44500000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b5050949350505050565b600080611511846120db565b905060006040518060400160405280601081526020017f67363d3d37363d34f03d5260086018f30000000000000000000000000000000081525090506000828251602084016000f5905073ffffffffffffffffffffffffffffffffffffffff81166115e0576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b604051839073ffffffffffffffffffffffffffffffffffffffff8316907f2feea65dd4e9f9cbd86b74b7734210c59a1b2981b5b137bd0ee3e208200c906790600090a361162c83610823565b935060008173ffffffffffffffffffffffffffffffffffffffff1634876040516116569190612d29565b60006040518083038185875af1925050503d8060008114611693576040519150601f19603f3d011682016040523d82523d6000602084013e611698565b606091505b505090506116a681866124ff565b60405173ffffffffffffffffffffffffffffffffffffffff8616907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a25050505092915050565b6000806116fd876120db565b9050808651602088018651f59150611714826123d3565b604051819073ffffffffffffffffffffffffffffffffffffffff8416907fb8fda7e00c6b06a2b54e58521bc5894fee35f1090e5a3bb6390bfe2b98b497f790600090a36000808373ffffffffffffffffffffffffffffffffffffffff168660200151886040516117849190612d29565b60006040518083038185875af1925050503d80600081146117c1576040519150601f19603f3d011682016040523d82523d6000602084013e6117c6565b606091505b509150915081611826577f0000000000000000000000000000000000000000000000000000000000000000816040517fa57ca23900000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163115611958578473ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163160405160006040518083038185875af1925050503d80600081146118f2576040519150601f19603f3d011682016040523d82523d6000602084013e6118f7565b606091505b50909250905081611958577f0000000000000000000000000000000000000000000000000000000000000000816040517fc2b3f44500000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b50505095945050505050565b60006107b36119e460408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b858585336116f1565b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b600080611a23876120db565b905060006040518060400160405280601081526020017f67363d3d37363d34f03d5260086018f30000000000000000000000000000000081525090506000828251602084016000f5905073ffffffffffffffffffffffffffffffffffffffff8116611af2576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b604051839073ffffffffffffffffffffffffffffffffffffffff8316907f2feea65dd4e9f9cbd86b74b7734210c59a1b2981b5b137bd0ee3e208200c906790600090a3611b3e83610823565b935060008173ffffffffffffffffffffffffffffffffffffffff1687600001518a604051611b6c9190612d29565b60006040518083038185875af1925050503d8060008114611ba9576040519150601f19603f3d011682016040523d82523d6000602084013e611bae565b606091505b50509050611bbc81866124ff565b60405173ffffffffffffffffffffffffffffffffffffffff8616907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a260608573ffffffffffffffffffffffffffffffffffffffff1688602001518a604051611c299190612d29565b60006040518083038185875af1925050503d8060008114611c66576040519150601f19603f3d011682016040523d82523d6000602084013e611c6b565b606091505b50909250905081611ccc577f0000000000000000000000000000000000000000000000000000000000000000816040517fa57ca23900000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163115611dfe578673ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163160405160006040518083038185875af1925050503d8060008114611d98576040519150601f19603f3d011682016040523d82523d6000602084013e611d9d565b606091505b50909250905081611dfe577f0000000000000000000000000000000000000000000000000000000000000000816040517fc2b3f44500000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b505050505095945050505050565b60006103dd611e8c60408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b868686866116f1565b60006103dd85858585336116f1565b60006103dd611f2460408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b86868686611a17565b6000808360601b90506040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528160148201527f5af43d82803e903d91602b57fd5bf3000000000000000000000000000000000060288201526037816000f092505073ffffffffffffffffffffffffffffffffffffffff8216612016576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b60405173ffffffffffffffffffffffffffffffffffffffff8316907f4db17dd5e4732fb6da34a148104a592783ca119a1e7bb8829eba6cbadef0b51190600090a26000808373ffffffffffffffffffffffffffffffffffffffff1634866040516120809190612d29565b60006040518083038185875af1925050503d80600081146120bd576040519150601f19603f3d011682016040523d82523d6000602084013e6120c2565b606091505b50915091506120d282828861247d565b50505092915050565b60008060006120e9846125b3565b9092509050600082600281111561210257612102612e02565b1480156121205750600081600281111561211e5761211e612e02565b145b1561215e57604080513360208201524691810191909152606081018590526080016040516020818303038152906040528051906020012092506123cc565b600082600281111561217257612172612e02565b1480156121905750600181600281111561218e5761218e612e02565b145b156121b0576121a9338560009182526020526040902090565b92506123cc565b60008260028111156121c4576121c4612e02565b03612233576040517f13b3a2a100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b600182600281111561224757612247612e02565b1480156122655750600081600281111561226357612263612e02565b145b1561227e576121a9468560009182526020526040902090565b600182600281111561229257612292612e02565b1480156122b0575060028160028111156122ae576122ae612e02565b145b1561231f576040517f13b3a2a100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b61239a60408051437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101406020830152419282019290925260608101919091524260808201524460a08201524660c08201523360e08201526000906101000160405160208183030381529060405280519060200120905090565b84036123a657836123c9565b604080516020810186905201604051602081830303815290604052805190602001205b92505b5050919050565b73ffffffffffffffffffffffffffffffffffffffff8116158061240b575073ffffffffffffffffffffffffffffffffffffffff81163b155b1561247a576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b50565b82158061249f575073ffffffffffffffffffffffffffffffffffffffff81163b155b156124fa577f0000000000000000000000000000000000000000000000000000000000000000826040517fa57ca23900000000000000000000000000000000000000000000000000000000815260040161062c929190612d94565b505050565b811580612520575073ffffffffffffffffffffffffffffffffffffffff8116155b80612540575073ffffffffffffffffffffffffffffffffffffffff81163b155b156125af576040517fc05cee7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016600482015260240161062c565b5050565b600080606083901c3314801561261057508260141a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f0100000000000000000000000000000000000000000000000000000000000000145b1561262057506000905080915091565b606083901c3314801561265a57507fff00000000000000000000000000000000000000000000000000000000000000601484901a60f81b16155b1561266b5750600090506001915091565b33606084901c036126825750600090506002915091565b606083901c1580156126db57508260141a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f0100000000000000000000000000000000000000000000000000000000000000145b156126ec5750600190506000915091565b606083901c15801561272557507fff00000000000000000000000000000000000000000000000000000000000000601484901a60f81b16155b1561273557506001905080915091565b606083901c61274a5750600190506002915091565b8260141a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f0100000000000000000000000000000000000000000000000000000000000000036127a55750600290506000915091565b8260141a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166000036127e15750600290506001915091565b506002905080915091565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261282c57600080fd5b813567ffffffffffffffff80821115612847576128476127ec565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561288d5761288d6127ec565b816040528381528660208588010111156128a657600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000604082840312156128d857600080fd5b6040516040810181811067ffffffffffffffff821117156128fb576128fb6127ec565b604052823581526020928301359281019290925250919050565b60008060008060a0858703121561292b57600080fd5b84359350602085013567ffffffffffffffff8082111561294a57600080fd5b6129568883890161281b565b9450604087013591508082111561296c57600080fd5b506129798782880161281b565b92505061298986606087016128c6565b905092959194509250565b600080604083850312156129a757600080fd5b82359150602083013567ffffffffffffffff8111156129c557600080fd5b6129d18582860161281b565b9150509250929050565b6000602082840312156129ed57600080fd5b813567ffffffffffffffff811115612a0457600080fd5b6107b38482850161281b565b803573ffffffffffffffffffffffffffffffffffffffff81168114612a3457600080fd5b919050565b600080600060608486031215612a4e57600080fd5b83359250612a5e60208501612a10565b9150604084013567ffffffffffffffff811115612a7a57600080fd5b612a868682870161281b565b9150509250925092565b600060208284031215612aa257600080fd5b5035919050565b600080600060808486031215612abe57600080fd5b833567ffffffffffffffff80821115612ad657600080fd5b612ae28783880161281b565b94506020860135915080821115612af857600080fd5b50612b058682870161281b565b925050612b1585604086016128c6565b90509250925092565b60008060408385031215612b3157600080fd5b82359150612b4160208401612a10565b90509250929050565b60008060408385031215612b5d57600080fd5b612b6683612a10565b946020939093013593505050565b60008060408385031215612b8757600080fd5b612b9083612a10565b9150602083013567ffffffffffffffff8111156129c557600080fd5b60008060408385031215612bbf57600080fd5b50508035926020909101359150565b60008060008060a08587031215612be457600080fd5b843567ffffffffffffffff80821115612bfc57600080fd5b612c088883890161281b565b95506020870135915080821115612c1e57600080fd5b50612c2b8782880161281b565b935050612c3b86604087016128c6565b915061298960808601612a10565b600080600080600060c08688031215612c6157600080fd5b85359450602086013567ffffffffffffffff80821115612c8057600080fd5b612c8c89838a0161281b565b95506040880135915080821115612ca257600080fd5b50612caf8882890161281b565b935050612cbf87606088016128c6565b9150612ccd60a08701612a10565b90509295509295909350565b600080600060608486031215612cee57600080fd5b8335925060208401359150612b1560408501612a10565b60005b83811015612d20578181015183820152602001612d08565b50506000910152565b60008251612d3b818460208701612d05565b9190910192915050565b67ffffffffffffffff828116828216039080821115612d8d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5092915050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260008251806040840152612dcf816060850160208701612d05565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016060019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea164736f6c6343000817000a1ca005f70bf8a1493291468f36ef23b05eb3a4f1807f6b4022942a4104b7537bfc36a029528c0c29546c81e7d78b0277ef87031541bdc96427b246ecedb6d74cd3ed62", "--rpc-url", &handle.http_endpoint()]) + .assert_success(); + cmd.forge_fuse() + .args([ + "script", + "script/CreateXScript.s.sol:CreateXScript", + "--rpc-url", + &handle.http_endpoint(), + "--slow", + "--sender", + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "--private-key", + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "--broadcast", + ]) + .assert_success(); +}); diff --git a/crates/forge/tests/fixtures/CreateXScript.sol b/crates/forge/tests/fixtures/CreateXScript.sol new file mode 100644 index 0000000000000..94180d39247e5 --- /dev/null +++ b/crates/forge/tests/fixtures/CreateXScript.sol @@ -0,0 +1,165 @@ +import "forge-std/Script.sol"; +import {Vm} from "forge-std/Vm.sol"; +contract CreateXGuardSaltMinimal { + enum SenderBytes { + MsgSender, + ZeroAddress, + Random + } + + enum RedeployProtectionFlag { + True, + False, + Unspecified + } + + error InvalidSalt(address emitter); + address internal constant _SELF = address(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed); + + function _guard(bytes32 salt) internal view returns (bytes32 guardedSalt) { + (SenderBytes senderBytes, RedeployProtectionFlag redeployProtectionFlag) = _parseSalt({salt: salt}); + + if (senderBytes == SenderBytes.MsgSender && redeployProtectionFlag == RedeployProtectionFlag.True) { + guardedSalt = keccak256(abi.encode(msg.sender, block.chainid, salt)); + } else if (senderBytes == SenderBytes.MsgSender && redeployProtectionFlag == RedeployProtectionFlag.False) { + guardedSalt = _efficientHash({a: bytes32(uint256(uint160(msg.sender))), b: salt}); + } else if (senderBytes == SenderBytes.MsgSender) { + revert InvalidSalt({emitter: _SELF}); + } else if (senderBytes == SenderBytes.ZeroAddress && redeployProtectionFlag == RedeployProtectionFlag.True) { + guardedSalt = _efficientHash({a: bytes32(block.chainid), b: salt}); + } else if ( + senderBytes == SenderBytes.ZeroAddress && redeployProtectionFlag == RedeployProtectionFlag.Unspecified + ) { + revert InvalidSalt({emitter: _SELF}); + } else { + guardedSalt = (salt != _generateSalt()) ? keccak256(abi.encode(salt)) : salt; + } + } + + function _parseSalt( + bytes32 salt + ) internal view returns (SenderBytes senderBytes, RedeployProtectionFlag redeployProtectionFlag) { + if (address(bytes20(salt)) == msg.sender && bytes1(salt[20]) == hex"01") { + (senderBytes, redeployProtectionFlag) = (SenderBytes.MsgSender, RedeployProtectionFlag.True); + } else if (address(bytes20(salt)) == msg.sender && bytes1(salt[20]) == hex"00") { + (senderBytes, redeployProtectionFlag) = (SenderBytes.MsgSender, RedeployProtectionFlag.False); + } else if (address(bytes20(salt)) == msg.sender) { + (senderBytes, redeployProtectionFlag) = (SenderBytes.MsgSender, RedeployProtectionFlag.Unspecified); + } else if (address(bytes20(salt)) == address(0) && bytes1(salt[20]) == hex"01") { + (senderBytes, redeployProtectionFlag) = (SenderBytes.ZeroAddress, RedeployProtectionFlag.True); + } else if (address(bytes20(salt)) == address(0) && bytes1(salt[20]) == hex"00") { + (senderBytes, redeployProtectionFlag) = (SenderBytes.ZeroAddress, RedeployProtectionFlag.False); + } else if (address(bytes20(salt)) == address(0)) { + (senderBytes, redeployProtectionFlag) = (SenderBytes.ZeroAddress, RedeployProtectionFlag.Unspecified); + } else if (bytes1(salt[20]) == hex"01") { + (senderBytes, redeployProtectionFlag) = (SenderBytes.Random, RedeployProtectionFlag.True); + } else if (bytes1(salt[20]) == hex"00") { + (senderBytes, redeployProtectionFlag) = (SenderBytes.Random, RedeployProtectionFlag.False); + } else { + (senderBytes, redeployProtectionFlag) = (SenderBytes.Random, RedeployProtectionFlag.Unspecified); + } + } + + + function _efficientHash(bytes32 a, bytes32 b) internal pure returns (bytes32 hash) { + assembly ("memory-safe") { + mstore(0x00, a) + mstore(0x20, b) + hash := keccak256(0x00, 0x40) + } + } + + +function _generateSalt() internal view returns (bytes32 salt) { + unchecked { + salt = keccak256( + abi.encode( + blockhash(block.number - 32), + block.coinbase, + block.number, + block.timestamp, + block.prevrandao, + block.chainid, + msg.sender + ) + ); + } + } +} + +interface CreateX { + function deployCreate3(bytes32 salt, bytes memory initCode) external payable returns (address newContract); + function computeCreate3Address(bytes32 salt) external view returns (address computedAddress); +} + +struct UNISWAP_ADDRESSES { + address payable UNISWAP_POSITION_MANAGER; + address UNISWAP_PERMIT2; + address UNISWAP_POOL_MANAGER; + address UNISWAP_STATE_VIEW; +} + +contract CreateXScript is Script, CreateXGuardSaltMinimal { + mapping(uint256 => UNISWAP_ADDRESSES) uniswapAddresses; + + function run() public { + bytes32 SALT = keccak256(hex"f39Fd6e51aad88F6F4ce6aB8827279cffFb922660077e9ad43da87c100f02196"); + + // // Local test, addresses mirror Base + uniswapAddresses[1616161] = UNISWAP_ADDRESSES({ + UNISWAP_POSITION_MANAGER: payable( + 0x7C5f5A4bBd8fD63184577525326123B519429bDc + ), + UNISWAP_PERMIT2: 0x000000000022D473030F116dDEE9F6B43aC78BA3, + UNISWAP_POOL_MANAGER: 0x498581fF718922c3f8e6A244956aF099B2652b2b, + UNISWAP_STATE_VIEW: 0xA3c0c9b65baD0b08107Aa264b0f3dB444b867A71 + }); + + + CreateX createx = CreateX(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed); + + address calculatedC1Address = createx.computeCreate3Address(_guard(bytes32(uint256(SALT) + 2))); + address calculatedC2Address = createx.computeCreate3Address(_guard(bytes32(uint256(SALT) + 1))); + + vm.startBroadcast(); + + bytes memory c0CreationCode = hex"60803461011457601f610f2b38819003918201601f19168301916001600160401b038311848410176101185780849260e094604052833981010312610114576100478161012c565b60208201519091906001600160a01b038116036101145760c081610070604061009e940161012c565b5061007d6060820161012c565b5061008a6080820161012c565b5061009760a0820161012c565b500161012c565b506001600160a01b03168015610101575f80546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3610dea90816101418239f35b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101145756fe6080806040526004361015610012575f80fd5b5f905f3560e01c9081630abd5fb9146109a457508063188b3c0f14610987578063222d23501461095f578063335abd45146109375780633c0299e51461090f57806346ae0668146108e75780634c25cf26146108ca57806351f18899146108a2578063527203e31461081357806359ac19c1146107c7578063691a0f1e146106555780636c3dd13e14610637578063715018a6146105dd578063787a08a6146105bf5780637c85a183146105a15780638a14117a146105835780638b211c02146105655780638da5cb5b1461053e578063a0beb08414610512578063aaba5271146104aa578063ad55af4b14610481578063b531d7f3146102d8578063ba405a0c146102af578063d2ca211514610291578063d6fbf20214610273578063dd7b883814610255578063e13cbe3814610237578063e2c6505614610219578063ea515b87146101f05763f2fde38b14610168575f80fd5b346101ed5760203660031901126101ed576101816109be565b610189610b6d565b6001600160a01b031680156101d95781546001600160a01b03198116821783556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b631e4fbdf760e01b82526004829052602482fd5b80fd5b50346101ed57806003193601126101ed576012546040516001600160a01b039091168152602090f35b50346101ed57806003193601126101ed576020600c54604051908152f35b50346101ed57806003193601126101ed576020601054604051908152f35b50346101ed57806003193601126101ed576020600854604051908152f35b50346101ed57806003193601126101ed576020600a54604051908152f35b50346101ed57806003193601126101ed576020600554604051908152f35b50346101ed57806003193601126101ed57600f546040516001600160a01b039091168152602090f35b50346101ed576101803660031901126101ed5760a435610124356001600160a01b03811690610104359060c4359083900361047d57610144356001600160a01b03811694908590036104795761032c610b6d565b8260011b8381046002148415171561043d57826b033b2e3c9fd0803ce8000000036b033b2e3c9fd0803ce800000081116104655761037381670de0b6b3a764000084610d02565b91846b033b2e3c9fd0803ce80000001461045157670de0b6b3a764000090091515810180911161043d57811061042e57600435600555602435600655604435600755606435600855608435600955600a55600d5560e435600b55600c556bffffffffffffffffffffffff60a01b600e541617600e556bffffffffffffffffffffffff60a01b600f541617600f55610164356010557fd9d41def84794db66ae5ab5d041caacb905afc49e9ca3604aa41bb1ea8a582e28180a180f35b635a2ee95360e11b8652600486fd5b634e487b7160e01b87526011600452602487fd5b634e487b7160e01b89526012600452602489fd5b634e487b7160e01b88526011600452602488fd5b8580fd5b8480fd5b50346101ed57806003193601126101ed576004546040516001600160a01b039091168152602090f35b50346101ed5760603660031901126101ed576044356104c7610b6d565b8015610503576004356014556024356013556015557f4bbf648868a599cc55656d8bca2c460f8c2136d467ea4c033a8aaaee493cdfbf8180a180f35b63166cb78960e01b8252600482fd5b50346101ed5760203660031901126101ed5760206105366105316109be565b610a1a565b604051908152f35b50346101ed57806003193601126101ed57546040516001600160a01b039091168152602090f35b50346101ed57806003193601126101ed576020600d54604051908152f35b50346101ed57806003193601126101ed576020600654604051908152f35b50346101ed57806003193601126101ed576020600b54604051908152f35b50346101ed57806003193601126101ed576020600754604051908152f35b50346101ed57806003193601126101ed576105f6610b6d565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346101ed57806003193601126101ed576020600954604051908152f35b503461075b57606036600319011261075b5761066f6109be565b600e5460243590604435906001600160a01b03163303610796576011546001600160a01b031692831561075f57833b1561075b575f80916064604051809481936324d5fda360e01b835260018060a01b0316988960048401528860248401528760448401525af1801561075057610715575b507f20dbc16160364bc8d282b93f41c769d3b024f0f8844f96fae2d74b2b71d844719160409182519182526020820152a280f35b6040919450916107465f7f20dbc16160364bc8d282b93f41c769d3b024f0f8844f96fae2d74b2b71d84471946109d4565b5f949150916106e1565b6040513d5f823e3d90fd5b5f80fd5b60405162461bcd60e51b815260206004820152600f60248201526e6e6f2d63756c742d666163746f727960881b6044820152606490fd5b60405162461bcd60e51b81526020600482015260096024820152686f6e6c792d686f6f6b60b81b6044820152606490fd5b3461075b575f36600319011261075b57600154600254600354600454604080516001600160a01b0395861681529385166020850152918416918301919091529091166060820152608090f35b3461075b575f36600319011261075b57610180600554600654600754600854600954600a54600d54600b5491600c549360018060a01b03600e54169560018060a01b03600f541697601054996040519b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e0860152610100850152610120840152610140830152610160820152f35b3461075b575f36600319011261075b576001546040516001600160a01b039091168152602090f35b3461075b575f36600319011261075b576020601554604051908152f35b3461075b575f36600319011261075b57600e546040516001600160a01b039091168152602090f35b3461075b575f36600319011261075b576011546040516001600160a01b039091168152602090f35b3461075b575f36600319011261075b576002546040516001600160a01b039091168152602090f35b3461075b575f36600319011261075b576003546040516001600160a01b039091168152602090f35b3461075b575f36600319011261075b576020601454604051908152f35b3461075b575f36600319011261075b576020906013548152f35b600435906001600160a01b038216820361075b57565b90601f8019910116810190811067ffffffffffffffff8211176109f657604052565b634e487b7160e01b5f52604160045260245ffd5b519062ffffff8216820361075b57565b600f546001600160a01b03908116908216808214610b5e57819282819210610b53575b5060018060a01b03600454169260405160a0810181811067ffffffffffffffff8211176109f65760809160a091604052600180831b0384168152600180831b0385166020820152610bb86040820152603c60608201525f8382015220602460405180978193633205590760e21b835260048301525afa938415610750575f94610ae5575b506001600160a01b03841615610add57610ada93610c51565b90565b505050505f90565b9093506080813d608011610b4b575b81610b01608093836109d4565b8101031261075b578051906001600160a01b038216820361075b5760208101518060020b0361075b57606081610b3c6040610b439401610a0a565b5001610a0a565b50925f610ac1565b3d9150610af4565b92508190505f610a3d565b505050670de0b6b3a764000090565b5f546001600160a01b03163303610b8057565b63118cdaa760e01b5f523360045260245ffd5b5f908015610c4b578080600114610c4357600214610c3c5760016101338210166001600b83101617610c2e579060019060025b60018111610bf25750825f19048211610bde57500290565b634e487b7160e01b81526011600452602490fd5b92805f19048111610c1a5760018416610c11575b80029260011c610bc6565b80920291610c06565b634e487b7160e01b82526011600452602482fd5b6002900a919080610bde5750565b5050600490565b505050600190565b50505f90565b5f9390926001600160a01b039182169291168203610cb75750610c7e916001600160a01b03169050610b93565b90610c96600160c01b670de0b6b3a764000084610d02565b91600160c01b90670de0b6b3a7640000900915158201809211610bde575090565b9192506001600160a01b0390911603610cf357610ada90610ce0906001600160a01b0316610b93565b670de0b6b3a7640000600160c01b610d02565b63e6f2de8760e01b5f5260045ffd5b91818302915f1981850993838086109503948086039514610d925784831115610d7a5790829109815f0382168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b82634e487b715f52156003026011186020526024601cfd5b505080925015610da0570490565b634e487b7160e01b5f52601260045260245ffdfea26469706673582212204c94689568baebf5fff57a2f3e072a1fb7067e2c83f098eac9e838fbfdded18664736f6c634300081a0033"; + + bytes memory c0DeploymentCode = abi.encodePacked( + c0CreationCode, + abi.encode( + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, + uniswapAddresses[block.chainid].UNISWAP_POSITION_MANAGER, + uniswapAddresses[block.chainid].UNISWAP_PERMIT2, + uniswapAddresses[block.chainid].UNISWAP_POOL_MANAGER, + uniswapAddresses[block.chainid].UNISWAP_STATE_VIEW, + calculatedC1Address, + calculatedC2Address + ) + ); + + address c0Address = createx.deployCreate3( + SALT, + c0DeploymentCode + ); + + + bytes memory c2CreationCode = hex"60803460b857601f6112a038819003918201601f19168301916001600160401b0383118484101760bc5780849260209460405283398101031260b857516001600160a01b0381169081900360b857801560a5575f80546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36111cf90816100d18239f35b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe6080806040526004361015610012575f80fd5b5f905f3560e01c9081630d31612614610f52575080631f94e50314610e4757806324d5fda314610ccb57806343fe85ba14610c8e5780634fb6df17146109c35780634ff013711461099a5780635eeb1bbc1461095b578063646ec81d1461086b5780636f8c57831461080a578063712232d5146107d1578063715018a61461077757806373c376581461073e5780637734d07614610685578063862a8eff146106445780638c730f2a146106185780638da5cb5b146105f1578063a05ff6b8146105ae578063aed19359146101bb578063d48418a1146101825763f2fde38b146100fa575f80fd5b3461017f57602036600319011261017f57610113610f86565b61011b6110de565b6001600160a01b0316801561016b5781546001600160a01b03198116821783556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b631e4fbdf760e01b82526004829052602482fd5b80fd5b503461017f57602036600319011261017f576020906040906001600160a01b036101aa610f86565b168152600883522054604051908152f35b503461017f57608036600319011261017f576101d5610f86565b9060243567ffffffffffffffff81116105aa576101f6903690600401610fd4565b60443567ffffffffffffffff81116105a657610216903690600401610fd4565b926064356001600160a01b038116908190036105a257835460405163ea515b8760e01b81526001600160a01b0390911695906020816004818a5afa908115610597578691610559575b506001600160a01b031693841561054a578560409461031d946102e360016020809b9a976102b9600583809a8e519b818d9251918291018484015e8101641021b7b4b760d91b838201520301601a1981018b520189610fb2565b8a519c818e9251918291018484015e8101604360f81b838201520301601e1981018c52018a610fb2565b61032f8751998a9788968795637b17ab9560e01b875260018060a01b0316600487015286602487015260c0604487015260c48601906110ba565b848103600319016064860152906110ba565b9060848301528260a483015203925af19182156104835781908293610502575b506001600160a01b0316808252600360209081526040808420805460ff191660011790555163188b3c0f60e01b8152939192919084600481885afa9384156104c35782946104ce575b5060018060a01b03169283825260066020526040822055604051630abd5fb960e01b8152602081600481885afa9081156104c3578291610490575b5060049460209185845260088352604084205560405195868092632612e79360e11b82525afa93841561048357819461044a575b50602083928195604084867fad5759c1cafdae1264943f6fa2482923381aa1c5fe5325f77329f99db30053ed9652600785522055604051908152a2604051908152f35b93506020843d60201161047b575b8161046560209383610fb2565b81010312610477579251926020610407565b5f80fd5b3d9150610458565b50604051903d90823e3d90fd5b90506020813d6020116104bb575b816104ab60209383610fb2565b81010312610477575160046103d3565b3d915061049e565b6040513d84823e3d90fd5b9093506020813d6020116104fa575b816104ea60209383610fb2565b810103126104775751925f610398565b3d91506104dd565b9250506040823d604011610542575b8161051e60409383610fb2565b8101031261017f5761053b6020610534846110a6565b93016110a6565b915f61034f565b3d9150610511565b6370b649dd60e01b8652600486fd5b90506020813d60201161058f575b8161057460209383610fb2565b8101031261058b57610585906110a6565b5f61025f565b8580fd5b3d9150610567565b6040513d88823e3d90fd5b8380fd5b8280fd5b5080fd5b503461017f57604036600319011261017f576020906040906001600160a01b036105d6610f86565b168152600a8352818120602435825283522054604051908152f35b503461017f578060031936011261017f57546040516001600160a01b039091168152602090f35b503461017f57602036600319011261017f57602061063c610637610f86565b61105b565b604051908152f35b503461017f57602036600319011261017f576020906001600160a01b03610669610f86565b16815260018252604060018060a01b0391205416604051908152f35b503461017f57606036600319011261017f5761069f610f86565b906106a8610f9c565b916106b16110de565b6001600160a01b03168082526002602052604082205490929060ff161561072f578282933b1561072b576040516340c10f1960e01b81526001600160a01b039290921660048301526044803560248401528391839190829084905af180156104c35761071a5750f35b8161072491610fb2565b61017f5780f35b5050fd5b638c5d908560e01b8252600482fd5b503461017f57602036600319011261017f576020906040906001600160a01b03610766610f86565b168152600783522054604051908152f35b503461017f578060031936011261017f576107906110de565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b503461017f57602036600319011261017f576020906040906001600160a01b036107f9610f86565b168152600683522054604051908152f35b503461017f57602036600319011261017f576080906040906001600160a01b03610832610f86565b16815260096020522060ff8154169060018101549060036002820154910154916040519315158452602084015260408301526060820152f35b503461017f57602036600319011261017f57610885610f86565b6004546001600160a01b0316330361094c576001600160a01b0316808252600260209081526040808420805460ff191660011790558284526005909152822054156108f2575b7fa4d13a5bef1890eddfd4d435735b46ed074a5e4b8f0a421cd526aeeef8141d3a8280a280f35b80825260056020524260408320558082526005602052807faed14053ca40d8865c112ef238ff360fe2189d5730000f57a6b88caf3198650e60408085205483865260076020528186205482519182526020820152a26108cb565b635651e6f560e11b8252600482fd5b503461017f57602036600319011261017f5760209060ff906040906001600160a01b03610986610f86565b168152600384522054166040519015158152f35b503461017f578060031936011261017f576004546040516001600160a01b039091168152602090f35b5034610477576040366003190112610477576109dd610f86565b602435908115610c7f576001600160a01b03165f818152600960205260409081902090516080810167ffffffffffffffff811182821017610c6b5760405260ff82541615801582526001830154916020810192835260606003600286015495604084019687520154910152610c5d57825f52600160205260018060a01b0360405f20541691825f52600260205260ff60405f20541615610c4e57815190835f52600a60205260405f20825f5260205260405f2054918215610c3f57845f52600660205260405f20548015610c305790879291865f52600860205260405f2054670de0b6b3a76400009290815b610bf0575050610af292610ae5610af7969593610aed93611104565b90519061102a565b61102a565b61103d565b8015610be157833b156104775760405163079cc67960e41b8152336004820152602481018690525f8160448183895af18015610bd657610bc1575b50823b1561058b576040516340c10f1960e01b8152336004820152602481018290528690818160448183895af180156104c357610bac575b505090516040805195865260208601929092529084015233927f142894e15d18cf7c1106a97eefe825087bf328fa8730129e3f89134321b3a23490606090a480f35b81610bb691610fb2565b61058b57855f610b6a565b610bce9196505f90610fb2565b5f945f610b32565b6040513d5f823e3d90fd5b639a57326560e01b5f5260045ffd5b909192939450600180831614610c1a575b80610c0b91611104565b899493929160011c9081610ac9565b92610c2884610c0b92611104565b939050610c01565b63374c934360e11b5f5260045ffd5b632959df1160e21b5f5260045ffd5b638c5d908560e01b5f5260045ffd5b62ad587d60e81b5f5260045ffd5b634e487b7160e01b5f52604160045260245ffd5b6313aab74360e01b5f5260045ffd5b34610477576020366003190112610477576001600160a01b03610caf610f86565b165f526002602052602060ff60405f2054166040519015158152f35b3461047757606036600319011261047757610ce4610f86565b60243560443591610cf36110de565b8115610e38578215610e29576001600160a01b039081165f8181526001602052604090205490939116918215610e1a57825f52600560205260405f205415610e0b57835f52600960205260405f2080549060ff8216610dfc57600384916001610d5b8861105b565b9460ff19161781558360018201558460028201550155610d7b838361102a565b92845f52600a60205260405f20825f5260205260405f20908154948501809511610de8577fc8ed84018dd91b7f9ef452fe95948d9dad8e47361ad1dd5886c54398e838e24094610de39255604051938493846040919493926060820195825260208201520152565b0390a3005b634e487b7160e01b5f52601160045260245ffd5b630931f96360e41b5f5260045ffd5b63277e703d60e21b5f5260045ffd5b63325ddddd60e01b5f5260045ffd5b639fbba64f60e01b5f5260045ffd5b637294708f60e11b5f5260045ffd5b3461047757604036600319011261047757610e60610f86565b610e68610f9c565b6004546001600160a01b03163303610f43576001600160a01b03169081158015610f32575b610f23576001600160a01b03165f8181526002602052604090205490919060ff1615610c4e575f818152600160205260409020546001600160a01b0316610f11575f81815260016020526040812080546001600160a01b031916841790557f0cb63fc6bb9f844b450c8052989a65f162ecac87757ca2c3921e0e9b7c4ccff69080a3005b631535136360e31b5f5260045260245ffd5b63e6c4247b60e01b5f5260045ffd5b506001600160a01b03811615610e8d565b635651e6f560e11b5f5260045ffd5b34610477576020366003190112610477576020906001600160a01b03610f76610f86565b165f526005825260405f20548152f35b600435906001600160a01b038216820361047757565b602435906001600160a01b038216820361047757565b90601f8019910116810190811067ffffffffffffffff821117610c6b57604052565b81601f820112156104775780359067ffffffffffffffff8211610c6b5760405192611009601f8401601f191660200185610fb2565b8284526020838301011161047757815f926020809301838601378301015290565b81810292918115918404141715610de857565b8115611047570490565b634e487b7160e01b5f52601260045260245ffd5b6001600160a01b03165f8181526005602052604090205415610e0b57805f52600560205260405f20544203428111610de8576110a3915f52600760205260405f20549061103d565b90565b51906001600160a01b038216820361047757565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b5f546001600160a01b031633036110f157565b63118cdaa760e01b5f523360045260245ffd5b9190915f838202915f19858209918380841093039280840393146111865782670de0b6b3a7640000111561117457507faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b634e487b71905260116020526024601cfd5b505050670de0b6b3a7640000919250049056fea2646970667358221220e8dac8dec112cb258e7bd8c159fd1da98ea741bb7b01073a1f31609d4cf729a064736f6c634300081a0033"; + bytes memory c2DeploymentCode = abi.encodePacked( + c2CreationCode, + abi.encode(c0Address) + ); + + address c2Address = createx.deployCreate3( + bytes32(uint256(SALT) + 1), + c2DeploymentCode + ); + + // Commenting out this check causes script to pass + if (c2Address != calculatedC2Address) { + console.log("address mismatch"); + } + + vm.stopBroadcast(); + } +} \ No newline at end of file diff --git a/testdata/default/repros/Issue4640.t.sol b/testdata/default/repros/Issue4640.t.sol index 1e7d887a9b57d..465e99a47c6fd 100644 --- a/testdata/default/repros/Issue4640.t.sol +++ b/testdata/default/repros/Issue4640.t.sol @@ -9,9 +9,9 @@ contract Issue4640Test is DSTest { Vm constant vm = Vm(HEVM_ADDRESS); function testArbitrumBlockNumber() public { - // - vm.createSelectFork("arbitrum", 75219831); + // + vm.createSelectFork("arbitrum", 394276729); // L1 block number - assertEq(block.number, 16939475); + assertEq(block.number, 23675778); } }