diff --git a/core/lib/basic_types/src/bytecode.rs b/core/lib/basic_types/src/bytecode.rs index cb6b54fcf3ce..12b4df69a6c6 100644 --- a/core/lib/basic_types/src/bytecode.rs +++ b/core/lib/basic_types/src/bytecode.rs @@ -266,7 +266,7 @@ mod tests { #[test] fn preparing_evm_bytecode() { let bytecode_hash = - BytecodeHash::for_evm_bytecode(PROCESSED_EVM_BYTECODE.len(), &PADDED_EVM_BYTECODE); + BytecodeHash::for_evm_bytecode(PROCESSED_EVM_BYTECODE.len(), PADDED_EVM_BYTECODE); let prepared = trim_padded_evm_bytecode(bytecode_hash, PADDED_EVM_BYTECODE).unwrap(); assert_eq!(prepared, PROCESSED_EVM_BYTECODE); } diff --git a/prover/crates/lib/keystore/src/utils.rs b/prover/crates/lib/keystore/src/utils.rs index 0492416af93f..ec68b33c58ce 100644 --- a/prover/crates/lib/keystore/src/utils.rs +++ b/prover/crates/lib/keystore/src/utils.rs @@ -183,7 +183,7 @@ mod tests { let filepath = basepath.join("commitments.json"); let text = std::fs::read_to_string(&filepath) - .expect(format!("File at {:?} should be read", filepath).as_str()); + .unwrap_or_else(|_| panic!("File at {:?} should be read", filepath)); let commitments = serde_json::from_str::(&text) .expect("Vk commitments should be deserialized correctly"); diff --git a/zkstack_cli/Cargo.lock b/zkstack_cli/Cargo.lock index 4e9bb4b1c76c..b31fc9f54421 100644 --- a/zkstack_cli/Cargo.lock +++ b/zkstack_cli/Cargo.lock @@ -235,6 +235,32 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "aws-lc-rs" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f409eb70b561706bf8abba8ca9c112729c481595893fd06a2dd9af8ed8441148" +dependencies = [ + "aws-lc-sys", + "paste", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8478a5c29ead3f3be14aff8a202ad965cf7da6856860041bfca271becf8ba48b" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", + "libc", + "paste", +] + [[package]] name = "axum" version = "0.7.9" @@ -338,6 +364,9 @@ name = "beef" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +dependencies = [ + "serde", +] [[package]] name = "bigdecimal" @@ -352,6 +381,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.89", + "which", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -534,6 +586,21 @@ dependencies = [ "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -571,6 +638,17 @@ dependencies = [ "inout", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.5.21" @@ -643,6 +721,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "cmake" +version = "0.1.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" +dependencies = [ + "cc", +] + [[package]] name = "coins-bip32" version = "0.8.7" @@ -701,11 +788,22 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "common" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", "clap", "cliclack", "console", @@ -724,6 +822,9 @@ dependencies = [ "types", "url", "xshell", + "zksync_system_constants", + "zksync_types", + "zksync_web3_decl", ] [[package]] @@ -1822,6 +1923,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "funty" version = "2.0.0" @@ -2000,6 +2107,27 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "gloo-net" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "http 0.2.12", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "gloo-timers" version = "0.2.6" @@ -2012,6 +2140,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "group" version = "0.13.0" @@ -2310,6 +2451,7 @@ dependencies = [ "http 1.1.0", "hyper 1.5.1", "hyper-util", + "log", "rustls 0.23.19", "rustls-pki-types", "tokio", @@ -2695,6 +2837,26 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "jobserver" version = "0.1.32" @@ -2713,6 +2875,149 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonrpsee" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b089779ad7f80768693755a031cc14a7766aba707cbe886674e3f79e9b7e47" +dependencies = [ + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-http-client", + "jsonrpsee-proc-macros", + "jsonrpsee-types", + "jsonrpsee-wasm-client", + "jsonrpsee-ws-client", + "tracing", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08163edd8bcc466c33d79e10f695cdc98c00d1e6ddfb95cec41b6b0279dd5432" +dependencies = [ + "base64 0.22.1", + "futures-channel", + "futures-util", + "gloo-net", + "http 1.1.0", + "jsonrpsee-core", + "pin-project", + "rustls 0.23.19", + "rustls-pki-types", + "rustls-platform-verifier", + "soketto", + "thiserror", + "tokio", + "tokio-rustls 0.26.0", + "tokio-util", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79712302e737d23ca0daa178e752c9334846b08321d439fd89af9a384f8c830b" +dependencies = [ + "anyhow", + "async-trait", + "beef", + "bytes", + "futures-timer", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "jsonrpsee-types", + "pin-project", + "rustc-hash 1.1.0", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "wasm-bindgen-futures", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d90064e04fb9d7282b1c71044ea94d0bbc6eff5621c66f1a0bce9e9de7cf3ac" +dependencies = [ + "async-trait", + "base64 0.22.1", + "http-body 1.0.1", + "hyper 1.5.1", + "hyper-rustls 0.27.3", + "hyper-util", + "jsonrpsee-core", + "jsonrpsee-types", + "rustls 0.23.19", + "rustls-platform-verifier", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower 0.4.13", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-proc-macros" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7895f186d5921065d96e16bd795e5ca89ac8356ec423fafc6e3d7cf8ec11aee4" +dependencies = [ + "heck", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c465fbe385238e861fdc4d1c85e04ada6c1fd246161d26385c1b311724d2af" +dependencies = [ + "beef", + "http 1.1.0", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonrpsee-wasm-client" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4727ac037f834c6f04c0912cada7532dbddb54e92fbc64e33d6cb8c24af313c9" +dependencies = [ + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", +] + +[[package]] +name = "jsonrpsee-ws-client" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c28759775f5cb2f1ea9667672d3fe2b0e701d1f4b7b67954e60afe7fd058b5e" +dependencies = [ + "http 1.1.0", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", + "url", +] + [[package]] name = "jsonwebtoken" version = "8.3.0" @@ -2812,12 +3117,28 @@ dependencies = [ "spin 0.9.8", ] +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.166" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36" +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + [[package]] name = "libm" version = "0.2.11" @@ -4094,7 +4415,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.25.4", "winreg", ] @@ -4239,6 +4560,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hash" version = "2.0.0" @@ -4291,13 +4618,29 @@ version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ + "aws-lc-rs", + "log", "once_cell", + "ring 0.17.8", "rustls-pki-types", "rustls-webpki 0.102.8", "subtle", "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -4322,6 +4665,33 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +[[package]] +name = "rustls-platform-verifier" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.19", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki 0.102.8", + "security-framework", + "security-framework-sys", + "webpki-roots 0.26.7", + "winapi", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -4338,6 +4708,7 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ + "aws-lc-rs", "ring 0.17.8", "rustls-pki-types", "untrusted 0.9.0", @@ -4485,6 +4856,7 @@ dependencies = [ "core-foundation", "core-foundation-sys", "libc", + "num-bigint", "security-framework-sys", ] @@ -4870,6 +5242,21 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "soketto" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures", + "httparse", + "log", + "rand", + "sha1", +] + [[package]] name = "solang-parser" version = "0.3.3" @@ -5142,7 +5529,7 @@ dependencies = [ "pretty_assertions", "rayon", "regex", - "rustc-hash", + "rustc-hash 2.0.0", "smol_str", "sqruff-lib-core", "sqruff-lib-dialects", @@ -5167,7 +5554,7 @@ dependencies = [ "itertools 0.13.0", "nohash-hasher", "pretty_assertions", - "rustc-hash", + "rustc-hash 2.0.0", "slyce", "smol_str", "sptr", @@ -5632,7 +6019,7 @@ dependencies = [ "tokio", "tokio-rustls 0.24.1", "tungstenite", - "webpki-roots", + "webpki-roots 0.25.4", ] [[package]] @@ -5643,6 +6030,7 @@ checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -6263,6 +6651,27 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "webpki-roots" +version = "0.26.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "whoami" version = "1.5.2" @@ -6746,6 +7155,9 @@ dependencies = [ "zksync_protobuf", "zksync_protobuf_build", "zksync_protobuf_config", + "zksync_system_constants", + "zksync_types", + "zksync_web3_decl", ] [[package]] @@ -7032,6 +7444,27 @@ dependencies = [ "vise-exporter", ] +[[package]] +name = "zksync_web3_decl" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "futures", + "jsonrpsee", + "pin-project-lite", + "rlp", + "rustls 0.23.19", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "vise", + "zksync_config", + "zksync_types", +] + [[package]] name = "zstd" version = "0.11.2+zstd.1.5.2" diff --git a/zkstack_cli/Cargo.toml b/zkstack_cli/Cargo.toml index 29a0e5bc43c6..c382e2059007 100644 --- a/zkstack_cli/Cargo.toml +++ b/zkstack_cli/Cargo.toml @@ -30,6 +30,10 @@ git_version_macro = { path = "crates/git_version_macro" } zksync_config = { path = "../core/lib/config" } zksync_protobuf_config = { path = "../core/lib/protobuf_config" } zksync_basic_types = { path = "../core/lib/basic_types" } +zksync_system_constants = { path = "../core/lib/constants" } +zksync_types = { path = "../core/lib/types" } +zksync_web3_decl = { path = "../core/lib/web3_decl" } +zksync_eth_client = { path = "../core/lib/eth_client" } zksync_consensus_roles = "=0.7.0" zksync_consensus_crypto = "=0.7.0" zksync_consensus_utils = "=0.7.0" @@ -68,3 +72,4 @@ url = { version = "2.5.0", features = ["serde"] } xshell = "0.2.6" clap-markdown = "0.1.4" secrecy = "0.8.0" +async-trait = "0.1.68" diff --git a/zkstack_cli/crates/common/Cargo.toml b/zkstack_cli/crates/common/Cargo.toml index 5fdf481bea6f..c906c3d28d04 100644 --- a/zkstack_cli/crates/common/Cargo.toml +++ b/zkstack_cli/crates/common/Cargo.toml @@ -30,3 +30,7 @@ xshell.workspace = true thiserror.workspace = true strum.workspace = true git_version_macro.workspace = true +async-trait.workspace = true +zksync_system_constants.workspace = true +zksync_types.workspace = true +zksync_web3_decl.workspace = true diff --git a/zkstack_cli/crates/common/src/forge.rs b/zkstack_cli/crates/common/src/forge.rs index bef285fb89b2..a7cf08a50bc0 100644 --- a/zkstack_cli/crates/common/src/forge.rs +++ b/zkstack_cli/crates/common/src/forge.rs @@ -121,6 +121,11 @@ impl ForgeScript { self } + pub fn with_zksync(mut self) -> Self { + self.args.add_arg(ForgeScriptArg::Zksync); + self + } + pub fn with_calldata(mut self, calldata: &Bytes) -> Self { self.args.add_arg(ForgeScriptArg::Sig { sig: hex::encode(calldata), @@ -128,6 +133,11 @@ impl ForgeScript { self } + pub fn with_gas_limit(mut self, gas_limit: u64) -> Self { + self.args.add_arg(ForgeScriptArg::GasLimit { gas_limit }); + self + } + /// Makes sure a transaction is sent, only after its previous one has been confirmed and succeeded. pub fn with_slow(mut self) -> Self { self.args.add_arg(ForgeScriptArg::Slow); @@ -253,6 +263,11 @@ pub enum ForgeScriptArg { Sender { address: String, }, + #[strum(to_string = "gas-limit={gas_limit}")] + GasLimit { + gas_limit: u64, + }, + Zksync, } /// ForgeScriptArgs is a set of arguments that can be passed to the forge script command. diff --git a/zkstack_cli/crates/common/src/lib.rs b/zkstack_cli/crates/common/src/lib.rs index 9680bdd8df39..92b8ebb9d15f 100644 --- a/zkstack_cli/crates/common/src/lib.rs +++ b/zkstack_cli/crates/common/src/lib.rs @@ -16,6 +16,7 @@ pub mod server; pub mod version; pub mod wallets; pub mod yaml; +pub mod zks_provider; pub use prerequisites::{ check_general_prerequisites, check_prerequisites, GCLOUD_PREREQUISITE, GPU_PREREQUISITES, diff --git a/zkstack_cli/crates/common/src/server.rs b/zkstack_cli/crates/common/src/server.rs index 40da1cf80325..7f8c2a90e589 100644 --- a/zkstack_cli/crates/common/src/server.rs +++ b/zkstack_cli/crates/common/src/server.rs @@ -40,6 +40,7 @@ impl Server { general_path: P, secrets_path: P, contracts_path: P, + gateway_contracts_config_path: Option

, mut additional_args: Vec, ) -> anyhow::Result<()> where @@ -56,6 +57,16 @@ impl Server { let uring = self.uring.then_some("--features=rocksdb/io-uring"); + let (gateway_config_param, gateway_config_path) = + if let Some(gateway_contracts_config_path) = gateway_contracts_config_path { + ( + Some("--gateway-contracts-config-path"), + Some(gateway_contracts_config_path), + ) + } else { + (None, None) + }; + let mut cmd = Cmd::new( cmd!( shell, @@ -65,6 +76,7 @@ impl Server { --config-path {general_path} --secrets-path {secrets_path} --contracts-config-path {contracts_path} + {gateway_config_param...} {gateway_config_path...} " ) .args(additional_args) diff --git a/zkstack_cli/crates/common/src/zks_provider.rs b/zkstack_cli/crates/common/src/zks_provider.rs new file mode 100644 index 000000000000..bdd1b426cc46 --- /dev/null +++ b/zkstack_cli/crates/common/src/zks_provider.rs @@ -0,0 +1,164 @@ +use async_trait::async_trait; +use ethers::{ + providers::ProviderError, + types::{Address, Bytes, H160, H256, U64}, +}; +use serde::{Deserialize, Serialize}; +use zksync_system_constants::L1_MESSENGER_ADDRESS; +use zksync_types::{ + api::{L2ToL1Log, L2ToL1LogProof, Log}, + ethabi, +}; +use zksync_web3_decl::{ + client::{Client, L2}, + namespaces::{EthNamespaceClient, ZksNamespaceClient}, +}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct FinalizeWithdrawalParams { + pub l2_batch_number: U64, + pub l2_message_index: U64, + pub l2_tx_number_in_block: U64, + pub message: Bytes, + pub sender: Address, + pub proof: L2ToL1LogProof, +} + +#[async_trait] +pub trait ZKSProvider { + async fn get_withdrawal_log( + &self, + withdrawal_hash: H256, + index: usize, + ) -> Result<(Log, U64), ProviderError>; + + async fn get_withdrawal_l2_to_l1_log( + &self, + withdrawal_hash: H256, + index: usize, + ) -> Result<(u64, L2ToL1Log), ProviderError>; + + async fn get_finalize_withdrawal_params( + &self, + withdrawal_hash: H256, + index: usize, + ) -> Result; +} + +#[async_trait] +impl ZKSProvider for Client +where + Client: ZksNamespaceClient + EthNamespaceClient, +{ + async fn get_withdrawal_log( + &self, + withdrawal_hash: H256, + index: usize, + ) -> Result<(Log, U64), ProviderError> { + let receipt = ::get_transaction_receipt(self, withdrawal_hash) + .await + .map_err(|e| { + ProviderError::CustomError(format!("Failed to get transaction receipt: {}", e)) + })?; + + let receipt = receipt + .ok_or_else(|| ProviderError::CustomError("Transaction is not mined!".into()))?; + + let l1_message_event_signature: H256 = ethabi::long_signature( + "L1MessageSent", + &[ + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Bytes, + ], + ); + + let log = receipt + .logs + .clone() + .into_iter() + .filter(|log| { + log.address == L1_MESSENGER_ADDRESS && log.topics[0] == l1_message_event_signature + }) + .nth(index) + .ok_or_else(|| ProviderError::CustomError("Log not found".into()))?; + + Ok(( + Log { + l1_batch_number: receipt.l1_batch_number, + ..log + }, + receipt.l1_batch_tx_index.unwrap_or_default(), + )) + } + + async fn get_withdrawal_l2_to_l1_log( + &self, + withdrawal_hash: H256, + index: usize, + ) -> Result<(u64, L2ToL1Log), ProviderError> { + let receipt = ::get_transaction_receipt(self, withdrawal_hash) + .await + .map_err(|e| { + ProviderError::CustomError(format!("Failed to get withdrawal log: {}", e)) + })?; + + if receipt.is_none() { + return Err(ProviderError::CustomError( + "Transaction is not mined!".into(), + )); + } + + let receipt = receipt.unwrap(); + let messages: Vec<(u64, L2ToL1Log)> = receipt + .l2_to_l1_logs + .into_iter() + .enumerate() + .filter(|(_, log)| log.sender == L1_MESSENGER_ADDRESS) + .map(|(i, log)| (i as u64, log)) + .collect(); + + messages.get(index).cloned().ok_or_else(|| { + ProviderError::CustomError("L2ToL1Log not found at specified index".into()) + }) + } + + async fn get_finalize_withdrawal_params( + &self, + withdrawal_hash: H256, + index: usize, + ) -> Result { + let (log, l1_batch_tx_id) = self.get_withdrawal_log(withdrawal_hash, index).await?; + let (l2_to_l1_log_index, _) = self + .get_withdrawal_l2_to_l1_log(withdrawal_hash, index) + .await?; + let sender = H160::from_slice(&log.topics[1][12..]); + let proof = ::get_l2_to_l1_log_proof( + self, + withdrawal_hash, + Some(l2_to_l1_log_index as usize), + ) + .await + .map_err(|e| { + ProviderError::CustomError(format!("Failed to get withdrawal log proof: {}", e)) + })? + .ok_or_else(|| ProviderError::CustomError("Log proof not found!".into()))?; + + let message = ethers::abi::decode(&[ethers::abi::ParamType::Bytes], &log.data.0) + .map_err(|e| ProviderError::CustomError(format!("Failed to decode log data: {}", e)))? + .remove(0) + .into_bytes() + .ok_or_else(|| { + ProviderError::CustomError("Failed to extract message from decoded data".into()) + })?; + + Ok(FinalizeWithdrawalParams { + l2_batch_number: log.l1_batch_number.unwrap_or_default(), + l2_message_index: proof.id.into(), + l2_tx_number_in_block: l1_batch_tx_id, + message: message.into(), + sender, + proof, + }) + } +} diff --git a/zkstack_cli/crates/config/src/chain.rs b/zkstack_cli/crates/config/src/chain.rs index c8fa0717dff5..cd93299cfc41 100644 --- a/zkstack_cli/crates/config/src/chain.rs +++ b/zkstack_cli/crates/config/src/chain.rs @@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize, Serializer}; use types::{BaseToken, L1BatchCommitmentMode, L1Network, ProverMode, WalletCreation}; use xshell::Shell; use zksync_basic_types::L2ChainId; +use zksync_config::configs::{GatewayChainConfig, GatewayConfig}; use crate::{ consts::{ @@ -108,6 +109,14 @@ impl ChainConfig { SecretsConfig::read_with_base_path(self.get_shell(), &self.configs) } + pub fn get_gateway_config(&self) -> anyhow::Result { + GatewayConfig::read_with_base_path(self.get_shell(), &self.configs) + } + + pub fn get_gateway_chain_config(&self) -> anyhow::Result { + GatewayChainConfig::read_with_base_path(self.get_shell(), &self.configs) + } + pub fn path_to_general_config(&self) -> PathBuf { self.configs.join(GENERAL_FILE) } @@ -132,7 +141,7 @@ impl ChainConfig { general_config.save_with_base_path(self.get_shell(), &self.configs) } - pub fn path_to_foundry(&self) -> PathBuf { + pub fn path_to_l1_foundry(&self) -> PathBuf { self.link_to_code.join(L1_CONTRACTS_FOUNDRY) } diff --git a/zkstack_cli/crates/config/src/consts.rs b/zkstack_cli/crates/config/src/consts.rs index c3efb4ac3e96..6c5dfc8165ce 100644 --- a/zkstack_cli/crates/config/src/consts.rs +++ b/zkstack_cli/crates/config/src/consts.rs @@ -20,6 +20,10 @@ pub(crate) const INITIAL_DEPLOYMENT_FILE: &str = "initial_deployments.yaml"; pub(crate) const ERC20_DEPLOYMENT_FILE: &str = "erc20_deployments.yaml"; /// Name of the contracts file pub const CONTRACTS_FILE: &str = "contracts.yaml"; +/// Name of the gateway contracts file +pub const GATEWAY_FILE: &str = "gateway.yaml"; +/// Name of the gateway contracts file +pub const GATEWAY_CHAIN_FILE: &str = "gateway_chain.yaml"; /// Main repository for the ZKsync project pub const ZKSYNC_ERA_GIT_REPO: &str = "https://github.com/matter-labs/zksync-era"; /// Name of the docker-compose file inside zksync repository diff --git a/zkstack_cli/crates/config/src/contracts.rs b/zkstack_cli/crates/config/src/contracts.rs index 79044a59f3af..bac17958e3b7 100644 --- a/zkstack_cli/crates/config/src/contracts.rs +++ b/zkstack_cli/crates/config/src/contracts.rs @@ -89,6 +89,10 @@ impl ContractsConfig { Ok(()) } + pub fn set_transaction_filterer(&mut self, transaction_filterer_addr: Address) { + self.l1.transaction_filterer_addr = Some(transaction_filterer_addr); + } + pub fn set_consensus_registry( &mut self, consensus_registry_output: &ConsensusRegistryOutput, @@ -130,8 +134,28 @@ pub struct EcosystemContracts { pub bridgehub_proxy_addr: Address, pub state_transition_proxy_addr: Address, pub transparent_proxy_admin_addr: Address, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub stm_deployment_tracker_proxy_addr: Option

, pub validator_timelock_addr: Address, pub diamond_cut_data: String, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub force_deployments_data: Option, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub native_token_vault_addr: Option
, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub l1_bytecodes_supplier_addr: Option
, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub expected_rollup_l2_da_validator: Option
, } impl ZkStackConfig for EcosystemContracts {} @@ -140,6 +164,10 @@ impl ZkStackConfig for EcosystemContracts {} pub struct BridgesContracts { pub erc20: BridgeContractsDefinition, pub shared: BridgeContractsDefinition, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub l1_nullifier_addr: Option
, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] @@ -156,18 +184,58 @@ pub struct L1Contracts { pub governance_addr: Address, #[serde(default)] pub chain_admin_addr: Address, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub access_control_restriction_addr: Option
, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub chain_proxy_admin_addr: Option
, pub multicall3_addr: Address, pub verifier_addr: Address, pub validator_timelock_addr: Address, pub base_token_addr: Address, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub base_token_asset_id: Option, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub rollup_l1_da_validator_addr: Option
, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub avail_l1_da_validator_addr: Option
, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub no_da_validium_l1_validator_addr: Option
, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub transaction_filterer_addr: Option
, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] pub struct L2Contracts { pub testnet_paymaster_addr: Address, pub default_l2_upgrader: Address, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub da_validator_addr: Option
, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub l2_native_token_vault_proxy_addr: Option
, pub consensus_registry: Option
, pub multicall3: Option
, pub legacy_shared_bridge_addr: Option
, pub timestamp_asserter_addr: Option
, + // `Option` to be able to parse configs from pre-gateway protocol version. + // TODO(EVM-927): not used without gateway version. + #[serde(skip_serializing_if = "Option::is_none")] + pub predeployed_l2_wrapped_base_token_address: Option
, } diff --git a/zkstack_cli/crates/config/src/ecosystem.rs b/zkstack_cli/crates/config/src/ecosystem.rs index c67aebf2a46c..5fe85b175de4 100644 --- a/zkstack_cli/crates/config/src/ecosystem.rs +++ b/zkstack_cli/crates/config/src/ecosystem.rs @@ -213,7 +213,7 @@ impl EcosystemConfig { ContractsConfig::read(self.get_shell(), self.config.join(CONTRACTS_FILE)) } - pub fn path_to_foundry(&self) -> PathBuf { + pub fn path_to_l1_foundry(&self) -> PathBuf { self.link_to_code.join(L1_CONTRACTS_FOUNDRY) } diff --git a/zkstack_cli/crates/config/src/forge_interface/deploy_gateway_ctm/input.rs b/zkstack_cli/crates/config/src/forge_interface/deploy_gateway_ctm/input.rs new file mode 100644 index 000000000000..8f35180077a2 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/deploy_gateway_ctm/input.rs @@ -0,0 +1,135 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use ethers::abi::Address; +use serde::{Deserialize, Serialize}; +use types::ProverMode; +use zksync_basic_types::{H256, U256}; +use zksync_config::GenesisConfig; + +use crate::{ + forge_interface::deploy_ecosystem::input::InitialDeploymentConfig, traits::ZkStackConfig, + ChainConfig, ContractsConfig, EcosystemConfig, +}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct DeployGatewayCTMInput { + bridgehub_proxy_addr: Address, + ctm_deployment_tracker_proxy_addr: Address, + native_token_vault_addr: Address, + chain_type_manager_proxy_addr: Address, + shared_bridge_proxy_addr: Address, + + governance: Address, + base_token: Address, + + chain_chain_id: U256, + era_chain_id: U256, + l1_chain_id: U256, + + testnet_verifier: bool, + + recursion_node_level_vk_hash: H256, + recursion_leaf_level_vk_hash: H256, + recursion_circuits_set_vks_hash: H256, + + diamond_init_pubdata_pricing_mode: u64, + diamond_init_batch_overhead_l1_gas: u64, + diamond_init_max_pubdata_per_batch: u64, + diamond_init_max_l2_gas_per_batch: u64, + diamond_init_priority_tx_max_pubdata: u64, + diamond_init_minimal_l2_gas_price: u64, + + bootloader_hash: H256, + default_aa_hash: H256, + + priority_tx_max_gas_limit: u64, + + genesis_root: H256, + genesis_rollup_leaf_index: u64, + genesis_batch_commitment: H256, + + latest_protocol_version: U256, + + force_deployments_data: String, + + expected_rollup_l2_da_validator: Address, +} + +impl ZkStackConfig for DeployGatewayCTMInput {} + +impl DeployGatewayCTMInput { + pub fn new( + chain_config: &ChainConfig, + ecosystem_config: &EcosystemConfig, + genesis_config: &GenesisConfig, + contracts_config: &ContractsConfig, + initial_deployment_config: &InitialDeploymentConfig, + ) -> Self { + Self { + bridgehub_proxy_addr: contracts_config.ecosystem_contracts.bridgehub_proxy_addr, + ctm_deployment_tracker_proxy_addr: contracts_config + .ecosystem_contracts + .stm_deployment_tracker_proxy_addr + .expect("stm_deployment_tracker_proxy_addr"), + native_token_vault_addr: contracts_config + .ecosystem_contracts + .native_token_vault_addr + .expect("native_token_vault_addr"), + chain_type_manager_proxy_addr: contracts_config + .ecosystem_contracts + .state_transition_proxy_addr, + shared_bridge_proxy_addr: contracts_config.bridges.shared.l1_address, + governance: ecosystem_config + .get_contracts_config() + .unwrap() + .l1 + .governance_addr, + + base_token: chain_config.base_token.address, + + chain_chain_id: U256::from(chain_config.chain_id.as_u64()), + era_chain_id: U256::from(ecosystem_config.era_chain_id.as_u64()), + l1_chain_id: U256::from(ecosystem_config.l1_network.chain_id()), + + testnet_verifier: ecosystem_config.prover_version == ProverMode::NoProofs, + + recursion_node_level_vk_hash: H256::zero(), + recursion_leaf_level_vk_hash: H256::zero(), + recursion_circuits_set_vks_hash: H256::zero(), + + diamond_init_pubdata_pricing_mode: initial_deployment_config + .diamond_init_pubdata_pricing_mode, + diamond_init_batch_overhead_l1_gas: initial_deployment_config + .diamond_init_batch_overhead_l1_gas, + diamond_init_max_pubdata_per_batch: initial_deployment_config + .diamond_init_max_pubdata_per_batch, + diamond_init_max_l2_gas_per_batch: initial_deployment_config + .diamond_init_max_l2_gas_per_batch, + diamond_init_priority_tx_max_pubdata: initial_deployment_config + .diamond_init_priority_tx_max_pubdata, + diamond_init_minimal_l2_gas_price: initial_deployment_config + .diamond_init_minimal_l2_gas_price, + + bootloader_hash: genesis_config.bootloader_hash.unwrap(), + default_aa_hash: genesis_config.default_aa_hash.unwrap(), + + priority_tx_max_gas_limit: initial_deployment_config.priority_tx_max_gas_limit, + + genesis_root: genesis_config.genesis_root_hash.unwrap(), + genesis_rollup_leaf_index: genesis_config.rollup_last_leaf_index.unwrap(), + genesis_batch_commitment: genesis_config.genesis_commitment.unwrap(), + + latest_protocol_version: genesis_config.protocol_version.unwrap().pack(), + + expected_rollup_l2_da_validator: contracts_config + .ecosystem_contracts + .expected_rollup_l2_da_validator + .unwrap(), + + force_deployments_data: contracts_config + .ecosystem_contracts + .force_deployments_data + .clone() + .expect("force_deployments_data"), + } + } +} diff --git a/zkstack_cli/crates/config/src/forge_interface/deploy_gateway_ctm/mod.rs b/zkstack_cli/crates/config/src/forge_interface/deploy_gateway_ctm/mod.rs new file mode 100644 index 000000000000..cb22b3529e85 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/deploy_gateway_ctm/mod.rs @@ -0,0 +1,3 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +pub mod input; +pub mod output; diff --git a/zkstack_cli/crates/config/src/forge_interface/deploy_gateway_ctm/output.rs b/zkstack_cli/crates/config/src/forge_interface/deploy_gateway_ctm/output.rs new file mode 100644 index 000000000000..ee85d11a5eb6 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/deploy_gateway_ctm/output.rs @@ -0,0 +1,32 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use ethers::abi::Address; +use serde::{Deserialize, Serialize}; + +use crate::traits::ZkStackConfig; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct DeployGatewayCTMOutput { + pub gateway_state_transition: StateTransitionDeployedAddresses, + pub multicall3_addr: Address, + pub validium_da_validator: Address, + pub relayed_sl_da_validator: Address, + pub diamond_cut_data: String, +} + +impl ZkStackConfig for DeployGatewayCTMOutput {} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct StateTransitionDeployedAddresses { + pub chain_type_manager_proxy_addr: Address, + pub chain_type_manager_implementation_addr: Address, + pub verifier_addr: Address, + pub admin_facet_addr: Address, + pub mailbox_facet_addr: Address, + pub executor_facet_addr: Address, + pub getters_facet_addr: Address, + pub diamond_init_addr: Address, + pub genesis_upgrade_addr: Address, + pub default_upgrade_addr: Address, + pub validator_timelock_addr: Address, + // The `diamond_proxy` field is removed as indicated by the TODO comment in the Solidity struct. +} diff --git a/zkstack_cli/crates/config/src/forge_interface/gateway_chain_upgrade/input.rs b/zkstack_cli/crates/config/src/forge_interface/gateway_chain_upgrade/input.rs new file mode 100644 index 000000000000..5fce7ebe3388 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/gateway_chain_upgrade/input.rs @@ -0,0 +1,51 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use ethers::types::Address; +use serde::{Deserialize, Serialize}; +use types::L1BatchCommitmentMode; +use zksync_basic_types::L2ChainId; + +use crate::{traits::ZkStackConfig, ChainConfig}; + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GatewayChainUpgradeInput { + // This should be the address that controls the current `ChainAdmin` + // contract + pub owner_address: Address, + pub chain: GatewayChainUpgradeChain, +} +impl ZkStackConfig for GatewayChainUpgradeInput {} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GatewayChainUpgradeChain { + pub chain_id: L2ChainId, + pub diamond_proxy_address: Address, + pub validium_mode: bool, + pub permanent_rollup: bool, +} + +impl GatewayChainUpgradeInput { + pub fn new(current_chain_config: &ChainConfig) -> Self { + let contracts_config = current_chain_config.get_contracts_config().unwrap(); + + let validum = current_chain_config + .get_genesis_config() + .unwrap() + .l1_batch_commit_data_generator_mode + == L1BatchCommitmentMode::Validium; + + Self { + owner_address: current_chain_config + .get_wallets_config() + .unwrap() + .governor + .address, + chain: GatewayChainUpgradeChain { + chain_id: current_chain_config.chain_id, + diamond_proxy_address: contracts_config.l1.diamond_proxy_addr, + validium_mode: validum, + // TODO(EVM-860): we assume that all rollup chains want to forever remain this way + permanent_rollup: !validum, + }, + } + } +} diff --git a/zkstack_cli/crates/config/src/forge_interface/gateway_chain_upgrade/mod.rs b/zkstack_cli/crates/config/src/forge_interface/gateway_chain_upgrade/mod.rs new file mode 100644 index 000000000000..cb22b3529e85 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/gateway_chain_upgrade/mod.rs @@ -0,0 +1,3 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +pub mod input; +pub mod output; diff --git a/zkstack_cli/crates/config/src/forge_interface/gateway_chain_upgrade/output.rs b/zkstack_cli/crates/config/src/forge_interface/gateway_chain_upgrade/output.rs new file mode 100644 index 000000000000..57c82effcc47 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/gateway_chain_upgrade/output.rs @@ -0,0 +1,14 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use ethers::types::Address; +use serde::{Deserialize, Serialize}; + +use crate::traits::ZkStackConfig; + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GatewayChainUpgradeOutput { + // This should be the address that controls the current `ChainAdmin` + // contract + pub chain_admin_addr: Address, + pub access_control_restriction: Address, +} +impl ZkStackConfig for GatewayChainUpgradeOutput {} diff --git a/zkstack_cli/crates/config/src/forge_interface/gateway_ecosystem_upgrade/input.rs b/zkstack_cli/crates/config/src/forge_interface/gateway_ecosystem_upgrade/input.rs new file mode 100644 index 000000000000..d71f327ede45 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/gateway_ecosystem_upgrade/input.rs @@ -0,0 +1,125 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use ethers::types::{Address, H256}; +use serde::{Deserialize, Serialize}; +use zksync_basic_types::L2ChainId; + +use crate::{ + forge_interface::deploy_ecosystem::input::InitialDeploymentConfig, traits::ZkStackConfig, + ContractsConfig, GenesisConfig, +}; + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GatewayEcosystemUpgradeInput { + pub era_chain_id: L2ChainId, + pub owner_address: Address, + pub testnet_verifier: bool, + pub contracts: GatewayUpgradeContractsConfig, + pub tokens: GatewayUpgradeTokensConfig, +} + +impl ZkStackConfig for GatewayEcosystemUpgradeInput {} + +impl GatewayEcosystemUpgradeInput { + pub fn new( + new_genesis_config: &GenesisConfig, + current_contracts_config: &ContractsConfig, + // It is expected to not change between the versions + initial_deployment_config: &InitialDeploymentConfig, + era_chain_id: L2ChainId, + era_diamond_proxy: Address, + testnet_verifier: bool, + ) -> Self { + Self { + era_chain_id, + testnet_verifier, + owner_address: current_contracts_config.l1.governance_addr, + contracts: GatewayUpgradeContractsConfig { + create2_factory_addr: initial_deployment_config.create2_factory_addr, + create2_factory_salt: initial_deployment_config.create2_factory_salt, + governance_min_delay: initial_deployment_config.governance_min_delay, + max_number_of_chains: initial_deployment_config.max_number_of_chains, + diamond_init_batch_overhead_l1_gas: initial_deployment_config + .diamond_init_batch_overhead_l1_gas, + diamond_init_max_l2_gas_per_batch: initial_deployment_config + .diamond_init_max_l2_gas_per_batch, + diamond_init_max_pubdata_per_batch: initial_deployment_config + .diamond_init_max_pubdata_per_batch, + diamond_init_minimal_l2_gas_price: initial_deployment_config + .diamond_init_minimal_l2_gas_price, + bootloader_hash: new_genesis_config.bootloader_hash.unwrap(), + default_aa_hash: new_genesis_config.default_aa_hash.unwrap(), + diamond_init_priority_tx_max_pubdata: initial_deployment_config + .diamond_init_priority_tx_max_pubdata, + diamond_init_pubdata_pricing_mode: initial_deployment_config + .diamond_init_pubdata_pricing_mode, + // These values are not optional in genesis config with file based configuration + genesis_batch_commitment: new_genesis_config.genesis_commitment.unwrap(), + genesis_rollup_leaf_index: new_genesis_config.rollup_last_leaf_index.unwrap(), + genesis_root: new_genesis_config.genesis_root_hash.unwrap(), + recursion_circuits_set_vks_hash: H256::zero(), + recursion_leaf_level_vk_hash: H256::zero(), + recursion_node_level_vk_hash: H256::zero(), + priority_tx_max_gas_limit: initial_deployment_config.priority_tx_max_gas_limit, + validator_timelock_execution_delay: initial_deployment_config + .validator_timelock_execution_delay, + + bridgehub_proxy_address: current_contracts_config + .ecosystem_contracts + .bridgehub_proxy_addr, + old_shared_bridge_proxy_address: current_contracts_config.bridges.shared.l1_address, + state_transition_manager_address: current_contracts_config + .ecosystem_contracts + .state_transition_proxy_addr, + transparent_proxy_admin: current_contracts_config + .ecosystem_contracts + .transparent_proxy_admin_addr, + era_diamond_proxy, + legacy_erc20_bridge_address: current_contracts_config.bridges.erc20.l1_address, + old_validator_timelock: current_contracts_config + .ecosystem_contracts + .validator_timelock_addr, + }, + tokens: GatewayUpgradeTokensConfig { + token_weth_address: initial_deployment_config.token_weth_address, + }, + } + } +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GatewayUpgradeContractsConfig { + pub governance_min_delay: u64, + pub max_number_of_chains: u64, + pub create2_factory_salt: H256, + #[serde(skip_serializing_if = "Option::is_none")] + pub create2_factory_addr: Option
, + pub validator_timelock_execution_delay: u64, + pub genesis_root: H256, + pub genesis_rollup_leaf_index: u64, + pub genesis_batch_commitment: H256, + pub recursion_node_level_vk_hash: H256, + pub recursion_leaf_level_vk_hash: H256, + pub recursion_circuits_set_vks_hash: H256, + pub priority_tx_max_gas_limit: u64, + pub diamond_init_pubdata_pricing_mode: u64, + pub diamond_init_batch_overhead_l1_gas: u64, + pub diamond_init_max_pubdata_per_batch: u64, + pub diamond_init_max_l2_gas_per_batch: u64, + pub diamond_init_priority_tx_max_pubdata: u64, + pub diamond_init_minimal_l2_gas_price: u64, + pub bootloader_hash: H256, + pub default_aa_hash: H256, + + pub bridgehub_proxy_address: Address, + pub old_shared_bridge_proxy_address: Address, + pub state_transition_manager_address: Address, + pub transparent_proxy_admin: Address, + pub era_diamond_proxy: Address, + pub legacy_erc20_bridge_address: Address, + pub old_validator_timelock: Address, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GatewayUpgradeTokensConfig { + pub token_weth_address: Address, +} diff --git a/zkstack_cli/crates/config/src/forge_interface/gateway_ecosystem_upgrade/mod.rs b/zkstack_cli/crates/config/src/forge_interface/gateway_ecosystem_upgrade/mod.rs new file mode 100644 index 000000000000..cb22b3529e85 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/gateway_ecosystem_upgrade/mod.rs @@ -0,0 +1,3 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +pub mod input; +pub mod output; diff --git a/zkstack_cli/crates/config/src/forge_interface/gateway_ecosystem_upgrade/output.rs b/zkstack_cli/crates/config/src/forge_interface/gateway_ecosystem_upgrade/output.rs new file mode 100644 index 000000000000..8f030eb47b73 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/gateway_ecosystem_upgrade/output.rs @@ -0,0 +1,94 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use ethers::types::{Address, H256}; +use serde::{Deserialize, Serialize}; +use zksync_basic_types::web3::Bytes; + +use crate::traits::{FileConfigWithDefaultName, ZkStackConfig}; + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GatewayEcosystemUpgradeOutput { + pub create2_factory_addr: Address, + pub create2_factory_salt: H256, + pub deployer_addr: Address, + pub era_chain_id: u32, + pub l1_chain_id: u32, + pub owner_address: Address, + pub chain_upgrade_diamond_cut: Bytes, + pub governance_stage1_calls: Bytes, + pub governance_stage2_calls: Bytes, + + pub contracts_config: GatewayEcosystemUpgradeContractsOutput, + pub deployed_addresses: GatewayEcosystemUpgradeDeployedAddresses, +} + +impl FileConfigWithDefaultName for GatewayEcosystemUpgradeOutput { + const FILE_NAME: &'static str = "gateway_ecosystem_upgrade_output.yaml"; +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GatewayEcosystemUpgradeContractsOutput { + pub diamond_cut_data: Bytes, + + pub diamond_init_batch_overhead_l1_gas: u64, + pub diamond_init_max_l2_gas_per_batch: u64, + pub diamond_init_max_pubdata_per_batch: u64, + pub diamond_init_minimal_l2_gas_price: u64, + pub diamond_init_priority_tx_max_pubdata: u64, + pub expected_rollup_l2_da_validator: Address, + pub expected_validium_l2_da_validator: Address, + + // Probably gonna need it to add new chains + pub force_deployments_data: Bytes, + + pub priority_tx_max_gas_limit: u64, + + pub recursion_circuits_set_vks_hash: H256, + pub recursion_leaf_level_vk_hash: H256, + pub recursion_node_level_vk_hash: H256, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GatewayEcosystemUpgradeDeployedAddresses { + pub native_token_vault_addr: Address, + pub rollup_l1_da_validator_addr: Address, + pub validator_timelock_addr: Address, + pub validium_l1_da_validator_addr: Address, + pub l1_bytecodes_supplier_addr: Address, + pub l2_wrapped_base_token_store_addr: Address, + + pub bridgehub: GatewayEcosystemUpgradeBridgehub, + pub bridges: GatewayEcosystemUpgradeBridges, + pub state_transition: GatewayEcosystemUpgradeStateTransition, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GatewayEcosystemUpgradeBridgehub { + pub bridgehub_implementation_addr: Address, + pub ctm_deployment_tracker_implementation_addr: Address, + pub ctm_deployment_tracker_proxy_addr: Address, + pub message_root_implementation_addr: Address, + pub message_root_proxy_addr: Address, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GatewayEcosystemUpgradeBridges { + pub erc20_bridge_implementation_addr: Address, + pub l1_nullifier_implementation_addr: Address, + pub shared_bridge_implementation_addr: Address, + pub shared_bridge_proxy_addr: Address, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct GatewayEcosystemUpgradeStateTransition { + pub admin_facet_addr: Address, + pub default_upgrade_addr: Address, + pub diamond_init_addr: Address, + pub executor_facet_addr: Address, + pub genesis_upgrade_addr: Address, + pub getters_facet_addr: Address, + pub mailbox_facet_addr: Address, + pub state_transition_implementation_addr: Address, + pub verifier_addr: Address, +} + +impl ZkStackConfig for GatewayEcosystemUpgradeOutput {} diff --git a/zkstack_cli/crates/config/src/forge_interface/gateway_preparation/input.rs b/zkstack_cli/crates/config/src/forge_interface/gateway_preparation/input.rs new file mode 100644 index 000000000000..263905d9fb35 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/gateway_preparation/input.rs @@ -0,0 +1,72 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use ethers::utils::hex; +use serde::{Deserialize, Serialize}; +use zksync_basic_types::{web3::Bytes, Address}; +use zksync_config::configs::GatewayConfig; + +use crate::{traits::ZkStackConfig, ChainConfig, ContractsConfig}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GatewayPreparationConfig { + pub bridgehub_proxy_addr: Address, + pub ctm_deployment_tracker_proxy_addr: Address, + pub chain_type_manager_proxy_addr: Address, + pub shared_bridge_proxy_addr: Address, + pub governance: Address, + pub chain_chain_id: u64, // Assuming uint256 can be represented as u64 for chain ID, use U256 for full uint256 support + pub gateway_diamond_cut_data: Bytes, + pub l1_diamond_cut_data: Bytes, + pub chain_proxy_admin: Address, + pub chain_admin: Address, + pub access_control_restriction: Address, + pub l1_nullifier_proxy_addr: Address, +} + +impl ZkStackConfig for GatewayPreparationConfig {} + +impl GatewayPreparationConfig { + pub fn new( + chain_config: &ChainConfig, + chain_contracts_config: &ContractsConfig, + ecosystem_contracts_config: &ContractsConfig, + gateway_config: &GatewayConfig, + ) -> anyhow::Result { + let contracts = chain_config.get_contracts_config()?; + + Ok(Self { + bridgehub_proxy_addr: contracts.ecosystem_contracts.bridgehub_proxy_addr, + chain_chain_id: chain_config.chain_id.as_u64(), + ctm_deployment_tracker_proxy_addr: contracts + .ecosystem_contracts + .stm_deployment_tracker_proxy_addr + .expect("stm_deployment_tracker_proxy_addr"), + chain_type_manager_proxy_addr: contracts + .ecosystem_contracts + .state_transition_proxy_addr, + shared_bridge_proxy_addr: contracts.bridges.shared.l1_address, + governance: ecosystem_contracts_config.l1.governance_addr, + gateway_diamond_cut_data: gateway_config.diamond_cut_data.clone(), + chain_proxy_admin: chain_contracts_config + .l1 + .chain_proxy_admin_addr + .expect("chain_proxy_admin_addr"), + chain_admin: chain_contracts_config.l1.chain_admin_addr, + access_control_restriction: chain_contracts_config + .l1 + .access_control_restriction_addr + .expect("access_control_restriction_addr"), + l1_nullifier_proxy_addr: chain_contracts_config + .bridges + .l1_nullifier_addr + .expect("l1_nullifier_addr"), + l1_diamond_cut_data: hex::decode( + chain_contracts_config + .ecosystem_contracts + .diamond_cut_data + .clone(), + ) + .unwrap() + .into(), + }) + } +} diff --git a/zkstack_cli/crates/config/src/forge_interface/gateway_preparation/mod.rs b/zkstack_cli/crates/config/src/forge_interface/gateway_preparation/mod.rs new file mode 100644 index 000000000000..cb22b3529e85 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/gateway_preparation/mod.rs @@ -0,0 +1,3 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +pub mod input; +pub mod output; diff --git a/zkstack_cli/crates/config/src/forge_interface/gateway_preparation/output.rs b/zkstack_cli/crates/config/src/forge_interface/gateway_preparation/output.rs new file mode 100644 index 000000000000..7d27725b2825 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/gateway_preparation/output.rs @@ -0,0 +1,15 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use serde::{Deserialize, Serialize}; +use zksync_basic_types::{Address, H256}; + +use crate::traits::ZkStackConfig; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GatewayPreparationOutput { + pub governance_l2_tx_hash: H256, + pub l2_chain_admin_address: Address, + pub gateway_transaction_filterer_implementation: Address, + pub gateway_transaction_filterer_proxy: Address, +} + +impl ZkStackConfig for GatewayPreparationOutput {} diff --git a/zkstack_cli/crates/config/src/forge_interface/mod.rs b/zkstack_cli/crates/config/src/forge_interface/mod.rs index c7033c45ed22..e1faa6980ecc 100644 --- a/zkstack_cli/crates/config/src/forge_interface/mod.rs +++ b/zkstack_cli/crates/config/src/forge_interface/mod.rs @@ -1,6 +1,10 @@ pub mod accept_ownership; pub mod deploy_ecosystem; +pub mod deploy_gateway_ctm; pub mod deploy_l2_contracts; +pub mod gateway_chain_upgrade; +pub mod gateway_ecosystem_upgrade; +pub mod gateway_preparation; pub mod paymaster; pub mod register_chain; pub mod script_params; diff --git a/zkstack_cli/crates/config/src/forge_interface/script_params.rs b/zkstack_cli/crates/config/src/forge_interface/script_params.rs index 9c84bbe431b4..eb693c83a54c 100644 --- a/zkstack_cli/crates/config/src/forge_interface/script_params.rs +++ b/zkstack_cli/crates/config/src/forge_interface/script_params.rs @@ -73,3 +73,42 @@ pub const ENABLE_EVM_EMULATOR_PARAMS: ForgeScriptParams = ForgeScriptParams { output: "script-out/output-enable-evm-emulator.toml", script_path: "deploy-scripts/EnableEvmEmulator.s.sol", }; + +// TODO(EVM-927): the following script does not work without gateway contracts. +pub const DEPLOY_GATEWAY_CTM: ForgeScriptParams = ForgeScriptParams { + input: "script-config/config-deploy-gateway-ctm.toml", + output: "script-out/output-deploy-gateway-ctm.toml", + script_path: "deploy-scripts/GatewayCTMFromL1.s.sol", +}; + +// TODO(EVM-927): the following script does not work without gateway contracts. +pub const GATEWAY_PREPARATION: ForgeScriptParams = ForgeScriptParams { + input: "script-config/gateway-preparation-l1.toml", + output: "script-out/output-gateway-preparation-l1.toml", + script_path: "deploy-scripts/GatewayPreparation.s.sol", +}; + +// TODO(EVM-927): the following script does not work without gateway contracts. +pub const GATEWAY_GOVERNANCE_TX_PATH1: &str = + "contracts/l1-contracts/script-out/gateway-deploy-governance-txs-1.json"; + +// TODO(EVM-927): the following script does not work without gateway contracts. +pub const GATEWAY_UPGRADE_ECOSYSTEM_PARAMS: ForgeScriptParams = ForgeScriptParams { + input: "script-config/gateway-upgrade-ecosystem.toml", + output: "script-out/gateway-upgrade-ecosystem.toml", + script_path: "deploy-scripts/upgrade/EcosystemUpgrade.s.sol", +}; + +// TODO(EVM-927): the following script does not work without gateway contracts. +pub const GATEWAY_UPGRADE_CHAIN_PARAMS: ForgeScriptParams = ForgeScriptParams { + input: "script-config/gateway-upgrade-chain.toml", + output: "script-out/gateway-upgrade-chain.toml", + script_path: "deploy-scripts/upgrade/ChainUpgrade.s.sol", +}; + +// TODO(EVM-927): the following script does not work without gateway contracts. +pub const FINALIZE_UPGRADE_SCRIPT_PARAMS: ForgeScriptParams = ForgeScriptParams { + input: "script-config/gateway-finalize-upgrade.toml", + output: "script-out/gateway-finalize-upgrade.toml", + script_path: "deploy-scripts/upgrade/FinalizeUpgrade.s.sol", +}; diff --git a/zkstack_cli/crates/config/src/gateway.rs b/zkstack_cli/crates/config/src/gateway.rs new file mode 100644 index 000000000000..0bdbcdf25475 --- /dev/null +++ b/zkstack_cli/crates/config/src/gateway.rs @@ -0,0 +1,47 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use ethers::utils::hex; +use zksync_config::configs::{gateway::GatewayChainConfig, GatewayConfig}; + +use crate::{ + forge_interface::deploy_gateway_ctm::output::DeployGatewayCTMOutput, + traits::{FileConfigWithDefaultName, ZkStackConfig}, + GATEWAY_CHAIN_FILE, GATEWAY_FILE, +}; + +impl FileConfigWithDefaultName for GatewayConfig { + const FILE_NAME: &'static str = GATEWAY_FILE; +} + +impl ZkStackConfig for GatewayConfig {} + +impl From for GatewayConfig { + fn from(output: DeployGatewayCTMOutput) -> Self { + GatewayConfig { + state_transition_proxy_addr: output + .gateway_state_transition + .chain_type_manager_proxy_addr, + state_transition_implementation_addr: output + .gateway_state_transition + .chain_type_manager_implementation_addr, + verifier_addr: output.gateway_state_transition.verifier_addr, + admin_facet_addr: output.gateway_state_transition.admin_facet_addr, + mailbox_facet_addr: output.gateway_state_transition.mailbox_facet_addr, + executor_facet_addr: output.gateway_state_transition.executor_facet_addr, + getters_facet_addr: output.gateway_state_transition.getters_facet_addr, + diamond_init_addr: output.gateway_state_transition.diamond_init_addr, + genesis_upgrade_addr: output.gateway_state_transition.genesis_upgrade_addr, + default_upgrade_addr: output.gateway_state_transition.default_upgrade_addr, + multicall3_addr: output.multicall3_addr, + diamond_cut_data: hex::decode(output.diamond_cut_data.clone()).unwrap().into(), + validator_timelock_addr: output.gateway_state_transition.validator_timelock_addr, + relayed_sl_da_validator: output.relayed_sl_da_validator, + validium_da_validator: output.validium_da_validator, + } + } +} + +impl FileConfigWithDefaultName for GatewayChainConfig { + const FILE_NAME: &'static str = GATEWAY_CHAIN_FILE; +} + +impl ZkStackConfig for GatewayChainConfig {} diff --git a/zkstack_cli/crates/config/src/lib.rs b/zkstack_cli/crates/config/src/lib.rs index b449aefe3a26..4d4fb8da61d2 100644 --- a/zkstack_cli/crates/config/src/lib.rs +++ b/zkstack_cli/crates/config/src/lib.rs @@ -18,6 +18,7 @@ mod consts; mod contracts; mod ecosystem; mod file_config; +mod gateway; mod general; mod genesis; mod manipulations; diff --git a/zkstack_cli/crates/zkstack/Cargo.toml b/zkstack_cli/crates/zkstack/Cargo.toml index 85ab8081eaa4..a19ced3f39c4 100644 --- a/zkstack_cli/crates/zkstack/Cargo.toml +++ b/zkstack_cli/crates/zkstack/Cargo.toml @@ -45,6 +45,9 @@ zksync_protobuf.workspace = true zksync_protobuf_config.workspace = true prost.workspace = true reqwest = "0.12.8" +zksync_types.workspace = true +zksync_web3_decl.workspace = true +zksync_system_constants.workspace = true [dev-dependencies] rand.workspace = true diff --git a/zkstack_cli/crates/zkstack/src/accept_ownership.rs b/zkstack_cli/crates/zkstack/src/accept_ownership.rs index 73dfd8082708..ab13661d6adb 100644 --- a/zkstack_cli/crates/zkstack/src/accept_ownership.rs +++ b/zkstack_cli/crates/zkstack/src/accept_ownership.rs @@ -1,12 +1,21 @@ +use anyhow::Context; use common::{ forge::{Forge, ForgeScript, ForgeScriptArgs}, spinner::Spinner, wallets::Wallet, }; -use config::{forge_interface::script_params::ACCEPT_GOVERNANCE_SCRIPT_PARAMS, EcosystemConfig}; -use ethers::{abi::parse_abi, contract::BaseContract, types::Address}; +use config::{ + forge_interface::script_params::ACCEPT_GOVERNANCE_SCRIPT_PARAMS, ChainConfig, ContractsConfig, + EcosystemConfig, +}; +use ethers::{ + abi::{parse_abi, Token}, + contract::BaseContract, + types::Address, +}; use lazy_static::lazy_static; use xshell::Shell; +use zksync_basic_types::U256; use crate::{ messages::MSG_ACCEPTING_GOVERNANCE_SPINNER, @@ -18,7 +27,6 @@ lazy_static! { parse_abi(&[ "function governanceAcceptOwner(address governor, address target) public", "function chainAdminAcceptAdmin(address admin, address target) public", - "function chainSetTokenMultiplierSetter(address chainAdmin, address target) public" ]) .unwrap(), ); @@ -42,7 +50,7 @@ pub async fn accept_admin( let calldata = ACCEPT_ADMIN .encode("chainAdminAcceptAdmin", (admin, target_address)) .unwrap(); - let foundry_contracts_path = ecosystem_config.path_to_foundry(); + let foundry_contracts_path = ecosystem_config.path_to_l1_foundry(); let forge = Forge::new(&foundry_contracts_path) .script( &ACCEPT_GOVERNANCE_SCRIPT_PARAMS.script(), @@ -71,7 +79,284 @@ pub async fn accept_owner( let calldata = ACCEPT_ADMIN .encode("governanceAcceptOwner", (governor_contract, target_address)) .unwrap(); - let foundry_contracts_path = ecosystem_config.path_to_foundry(); + let foundry_contracts_path = ecosystem_config.path_to_l1_foundry(); + let forge = Forge::new(&foundry_contracts_path) + .script( + &ACCEPT_GOVERNANCE_SCRIPT_PARAMS.script(), + forge_args.clone(), + ) + .with_ffi() + .with_rpc_url(l1_rpc_url) + .with_broadcast() + .with_calldata(&calldata); + accept_ownership(shell, governor, forge).await +} + +// TODO(EVM-927): this function does not work without the Gateway contracts. +#[allow(unused)] +#[allow(clippy::too_many_arguments)] +pub async fn set_da_validator_pair( + shell: &Shell, + ecosystem_config: &EcosystemConfig, + chain_admin_addr: Address, + governor: &Wallet, + diamond_proxy_address: Address, + l1_da_validator_address: Address, + l2_da_validator_address: Address, + forge_args: &ForgeScriptArgs, + l1_rpc_url: String, +) -> anyhow::Result<()> { + // TODO(EVM-927): this function does not work without the Gateway contracts. + anyhow::bail!("Gateway upgrade not supported yet!"); + + // resume doesn't properly work here. + let mut forge_args = forge_args.clone(); + forge_args.resume = false; + + let calldata = ACCEPT_ADMIN + .encode( + "setDAValidatorPair", + ( + chain_admin_addr, + diamond_proxy_address, + l1_da_validator_address, + l2_da_validator_address, + ), + ) + .unwrap(); + let foundry_contracts_path = ecosystem_config.path_to_l1_foundry(); + let forge = Forge::new(&foundry_contracts_path) + .script( + &ACCEPT_GOVERNANCE_SCRIPT_PARAMS.script(), + forge_args.clone(), + ) + .with_ffi() + .with_rpc_url(l1_rpc_url) + .with_broadcast() + .with_calldata(&calldata); + accept_ownership(shell, governor, forge).await +} + +// TODO(EVM-927): this function does not work without the Gateway contracts. +#[allow(unused)] +#[allow(clippy::too_many_arguments)] +pub async fn make_permanent_rollup( + shell: &Shell, + ecosystem_config: &EcosystemConfig, + chain_admin_addr: Address, + governor: &Wallet, + diamond_proxy_address: Address, + forge_args: &ForgeScriptArgs, + l1_rpc_url: String, +) -> anyhow::Result<()> { + // TODO(EVM-927): this function does not work without the Gateway contracts. + anyhow::bail!("Gateway upgrade not supported yet!"); + + // resume doesn't properly work here. + let mut forge_args = forge_args.clone(); + forge_args.resume = false; + + let calldata = ACCEPT_ADMIN + .encode( + "makePermanentRollup", + (chain_admin_addr, diamond_proxy_address), + ) + .unwrap(); + let foundry_contracts_path = ecosystem_config.path_to_l1_foundry(); + let forge = Forge::new(&foundry_contracts_path) + .script( + &ACCEPT_GOVERNANCE_SCRIPT_PARAMS.script(), + forge_args.clone(), + ) + .with_ffi() + .with_rpc_url(l1_rpc_url) + .with_broadcast() + .with_calldata(&calldata); + accept_ownership(shell, governor, forge).await +} + +// TODO(EVM-927): this function does not work without the Gateway contracts. +#[allow(unused)] +#[allow(clippy::too_many_arguments)] +pub async fn governance_execute_calls( + shell: &Shell, + ecosystem_config: &EcosystemConfig, + governor: &Wallet, + encoded_calls: Vec, + forge_args: &ForgeScriptArgs, + l1_rpc_url: String, +) -> anyhow::Result<()> { + // TODO(EVM-927): this function does not work without the Gateway contracts. + anyhow::bail!("Gateway upgrade not supported yet!"); + + // resume doesn't properly work here. + let mut forge_args = forge_args.clone(); + forge_args.resume = false; + + let governance_address = ecosystem_config.get_contracts_config()?.l1.governance_addr; + + let calldata = ACCEPT_ADMIN + .encode( + "governanceExecuteCalls", + (Token::Bytes(encoded_calls), governance_address), + ) + .unwrap(); + let foundry_contracts_path = ecosystem_config.path_to_l1_foundry(); + let forge = Forge::new(&foundry_contracts_path) + .script( + &ACCEPT_GOVERNANCE_SCRIPT_PARAMS.script(), + forge_args.clone(), + ) + .with_ffi() + .with_rpc_url(l1_rpc_url) + .with_broadcast() + .with_calldata(&calldata); + accept_ownership(shell, governor, forge).await +} + +// TODO(EVM-927): this function does not work without the Gateway contracts. +#[allow(unused)] +#[allow(clippy::too_many_arguments)] +pub async fn admin_execute_upgrade( + shell: &Shell, + ecosystem_config: &EcosystemConfig, + chain_contracts_config: &ContractsConfig, + governor: &Wallet, + upgrade_diamond_cut: Vec, + forge_args: &ForgeScriptArgs, + l1_rpc_url: String, +) -> anyhow::Result<()> { + // TODO(EVM-927): this function does not work without the Gateway contracts. + anyhow::bail!("Gateway upgrade not supported yet!"); + + // resume doesn't properly work here. + let mut forge_args = forge_args.clone(); + forge_args.resume = false; + + let admin_addr = chain_contracts_config.l1.chain_admin_addr; + let access_control_restriction = chain_contracts_config + .l1 + .access_control_restriction_addr + .context("no access_control_restriction_addr")?; + let diamond_proxy = chain_contracts_config.l1.diamond_proxy_addr; + + let calldata = ACCEPT_ADMIN + .encode( + "adminExecuteUpgrade", + ( + Token::Bytes(upgrade_diamond_cut), + admin_addr, + access_control_restriction, + diamond_proxy, + ), + ) + .unwrap(); + let foundry_contracts_path = ecosystem_config.path_to_l1_foundry(); + let forge = Forge::new(&foundry_contracts_path) + .script( + &ACCEPT_GOVERNANCE_SCRIPT_PARAMS.script(), + forge_args.clone(), + ) + .with_ffi() + .with_rpc_url(l1_rpc_url) + .with_broadcast() + .with_calldata(&calldata); + accept_ownership(shell, governor, forge).await +} + +// TODO(EVM-927): this function does not work without the Gateway contracts. +#[allow(unused)] +#[allow(clippy::too_many_arguments)] +pub async fn admin_schedule_upgrade( + shell: &Shell, + ecosystem_config: &EcosystemConfig, + chain_contracts_config: &ContractsConfig, + new_protocol_version: U256, + timestamp: U256, + governor: &Wallet, + forge_args: &ForgeScriptArgs, + l1_rpc_url: String, +) -> anyhow::Result<()> { + // TODO(EVM-927): this function does not work without the Gateway contracts. + anyhow::bail!("Gateway upgrade not supported yet!"); + + // resume doesn't properly work here. + let mut forge_args = forge_args.clone(); + forge_args.resume = false; + + let admin_addr = chain_contracts_config.l1.chain_admin_addr; + let access_control_restriction = chain_contracts_config + .l1 + .access_control_restriction_addr + .context("no access_control_restriction_addr")?; + + let calldata = ACCEPT_ADMIN + .encode( + "adminScheduleUpgrade", + ( + admin_addr, + access_control_restriction, + new_protocol_version, + timestamp, + ), + ) + .unwrap(); + let foundry_contracts_path = ecosystem_config.path_to_l1_foundry(); + let forge = Forge::new(&foundry_contracts_path) + .script( + &ACCEPT_GOVERNANCE_SCRIPT_PARAMS.script(), + forge_args.clone(), + ) + .with_ffi() + .with_rpc_url(l1_rpc_url) + .with_broadcast() + .with_calldata(&calldata); + accept_ownership(shell, governor, forge).await +} + +// TODO(EVM-927): this function does not work without the Gateway contracts. +#[allow(unused)] +#[allow(clippy::too_many_arguments)] +pub async fn admin_update_validator( + shell: &Shell, + ecosystem_config: &EcosystemConfig, + chain_config: &ChainConfig, + validator_timelock: Address, + validator: Address, + add_validator: bool, + governor: &Wallet, + forge_args: &ForgeScriptArgs, + l1_rpc_url: String, +) -> anyhow::Result<()> { + // TODO(EVM-927): this function does not work without the Gateway contracts. + anyhow::bail!("Gateway upgrade not supported yet!"); + + // resume doesn't properly work here. + let mut forge_args = forge_args.clone(); + forge_args.resume = false; + + let chain_contracts_config = chain_config.get_contracts_config()?; + + let admin_addr = chain_contracts_config.l1.chain_admin_addr; + let access_control_restriction = chain_contracts_config + .l1 + .access_control_restriction_addr + .context("no access_control_restriction_addr")?; + + let calldata = ACCEPT_ADMIN + .encode( + "updateValidator", + ( + admin_addr, + access_control_restriction, + validator_timelock, + chain_config.chain_id.as_u64(), + validator, + add_validator, + ), + ) + .unwrap(); + let foundry_contracts_path = ecosystem_config.path_to_l1_foundry(); let forge = Forge::new(&foundry_contracts_path) .script( &ACCEPT_GOVERNANCE_SCRIPT_PARAMS.script(), diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/convert_to_gateway.rs b/zkstack_cli/crates/zkstack/src/commands/chain/convert_to_gateway.rs new file mode 100644 index 000000000000..3043f3a52837 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/chain/convert_to_gateway.rs @@ -0,0 +1,428 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use anyhow::Context; +use common::{ + config::global_config, + forge::{Forge, ForgeScriptArgs}, + wallets::Wallet, +}; +use config::{ + forge_interface::{ + deploy_ecosystem::input::InitialDeploymentConfig, + deploy_gateway_ctm::{input::DeployGatewayCTMInput, output::DeployGatewayCTMOutput}, + gateway_preparation::{input::GatewayPreparationConfig, output::GatewayPreparationOutput}, + script_params::{DEPLOY_GATEWAY_CTM, GATEWAY_GOVERNANCE_TX_PATH1, GATEWAY_PREPARATION}, + }, + traits::{ReadConfig, SaveConfig, SaveConfigWithBasePath}, + ChainConfig, EcosystemConfig, GenesisConfig, +}; +use ethers::{abi::parse_abi, contract::BaseContract, types::Bytes, utils::hex}; +use lazy_static::lazy_static; +use xshell::Shell; +use zksync_basic_types::H256; +use zksync_config::configs::GatewayConfig; + +use crate::{ + messages::{MSG_CHAIN_NOT_INITIALIZED, MSG_L1_SECRETS_MUST_BE_PRESENTED}, + utils::forge::{check_the_balance, fill_forge_private_key, WalletOwner}, +}; + +lazy_static! { + pub static ref GATEWAY_PREPARATION_INTERFACE: BaseContract = BaseContract::from( + parse_abi(&[ + "function governanceRegisterGateway() public", + "function deployAndSetGatewayTransactionFilterer() public", + "function governanceWhitelistGatewayCTM(address gatewaySTMAddress, bytes32 governanoceOperationSalt) public", + "function governanceSetCTMAssetHandler(bytes32 governanoceOperationSalt)", + "function registerAssetIdInBridgehub(address gatewaySTMAddress, bytes32 governanoceOperationSalt)", + "function grantWhitelist(address filtererProxy, address[] memory addr) public", + "function executeGovernanceTxs() public" + ]) + .unwrap(), + ); + + static ref DEPLOY_GATEWAY_CTM_INTERFACE: BaseContract = BaseContract::from( + parse_abi(&[ + "function prepareAddresses() public", + "function deployCTM() public", + ]) + .unwrap(), + ); +} + +#[allow(unused)] +pub async fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { + // TODO(EVM-927): this function does not work without the Gateway contracts. + anyhow::bail!("Gateway upgrade not supported yet!"); + + let chain_name = global_config().chain_name.clone(); + let ecosystem_config = EcosystemConfig::from_file(shell)?; + let chain_config = ecosystem_config + .load_chain(chain_name) + .context(MSG_CHAIN_NOT_INITIALIZED)?; + let l1_url = chain_config + .get_secrets_config()? + .l1 + .context(MSG_L1_SECRETS_MUST_BE_PRESENTED)? + .l1_rpc_url + .expose_str() + .to_string(); + let mut chain_contracts_config = chain_config.get_contracts_config()?; + let chain_genesis_config = chain_config.get_genesis_config()?; + + // Firstly, deploying gateway contracts + let gateway_config = calculate_gateway_ctm( + shell, + args.clone(), + &ecosystem_config, + &chain_config, + &chain_genesis_config, + &ecosystem_config.get_initial_deployment_config().unwrap(), + l1_url.clone(), + ) + .await?; + + let gateway_preparation_config_path = GATEWAY_PREPARATION.input(&chain_config.link_to_code); + let preparation_config = GatewayPreparationConfig::new( + &chain_config, + &chain_contracts_config, + &ecosystem_config.get_contracts_config()?, + &gateway_config, + )?; + preparation_config.save(shell, gateway_preparation_config_path)?; + + gateway_governance_whitelisting( + shell, + args.clone(), + &ecosystem_config, + &chain_config, + gateway_config, + l1_url.clone(), + true, + ) + .await?; + + let output = call_script( + shell, + args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode("deployAndSetGatewayTransactionFilterer", ()) + .unwrap(), + &ecosystem_config, + &chain_config, + &chain_config.get_wallets_config()?.governor, + l1_url.clone(), + true, + ) + .await?; + + chain_contracts_config.set_transaction_filterer(output.gateway_transaction_filterer_proxy); + + // We could've deployed the CTM at the beginning however, to be closer to how the actual upgrade + // looks like we'll do it as the last step + + call_script( + shell, + args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode( + "grantWhitelist", + ( + output.gateway_transaction_filterer_proxy, + vec![ + ecosystem_config.get_contracts_config()?.l1.governance_addr, + ecosystem_config + .get_wallets()? + .deployer + .context("no deployer addr")? + .address, + ], + ), + ) + .unwrap(), + &ecosystem_config, + &chain_config, + &chain_config.get_wallets_config()?.governor, + l1_url.clone(), + true, + ) + .await?; + + deploy_gateway_ctm( + shell, + args, + &ecosystem_config, + &chain_config, + &chain_genesis_config, + &ecosystem_config.get_initial_deployment_config().unwrap(), + l1_url, + ) + .await?; + + chain_contracts_config.save_with_base_path(shell, chain_config.configs)?; + + Ok(()) +} + +async fn calculate_gateway_ctm( + shell: &Shell, + forge_args: ForgeScriptArgs, + config: &EcosystemConfig, + chain_config: &ChainConfig, + chain_genesis_config: &GenesisConfig, + initial_deployemnt_config: &InitialDeploymentConfig, + l1_rpc_url: String, +) -> anyhow::Result { + let contracts_config = chain_config.get_contracts_config()?; + let deploy_config_path = DEPLOY_GATEWAY_CTM.input(&config.link_to_code); + + let deploy_config = DeployGatewayCTMInput::new( + chain_config, + config, + chain_genesis_config, + &contracts_config, + initial_deployemnt_config, + ); + deploy_config.save(shell, deploy_config_path)?; + + let calldata = DEPLOY_GATEWAY_CTM_INTERFACE + .encode("prepareAddresses", ()) + .unwrap(); + + let mut forge = Forge::new(&config.path_to_l1_foundry()) + .script(&DEPLOY_GATEWAY_CTM.script(), forge_args.clone()) + .with_ffi() + .with_rpc_url(l1_rpc_url) + .with_calldata(&calldata) + .with_broadcast(); + + // Governor private key should not be needed for this script + forge = fill_forge_private_key( + forge, + config.get_wallets()?.deployer.as_ref(), + WalletOwner::Deployer, + )?; + check_the_balance(&forge).await?; + forge.run(shell)?; + + let register_chain_output = + DeployGatewayCTMOutput::read(shell, DEPLOY_GATEWAY_CTM.output(&chain_config.link_to_code))?; + + let gateway_config: GatewayConfig = register_chain_output.into(); + + gateway_config.save_with_base_path(shell, chain_config.configs.clone())?; + + Ok(gateway_config) +} + +async fn deploy_gateway_ctm( + shell: &Shell, + forge_args: ForgeScriptArgs, + config: &EcosystemConfig, + chain_config: &ChainConfig, + chain_genesis_config: &GenesisConfig, + initial_deployemnt_config: &InitialDeploymentConfig, + l1_rpc_url: String, +) -> anyhow::Result<()> { + let contracts_config = chain_config.get_contracts_config()?; + // let contracts_config = config.get_contracts_config()?; + let deploy_config_path = DEPLOY_GATEWAY_CTM.input(&config.link_to_code); + + let deploy_config = DeployGatewayCTMInput::new( + chain_config, + config, + chain_genesis_config, + &contracts_config, + initial_deployemnt_config, + ); + deploy_config.save(shell, deploy_config_path)?; + + let calldata = DEPLOY_GATEWAY_CTM_INTERFACE + .encode("deployCTM", ()) + .unwrap(); + + let mut forge = Forge::new(&config.path_to_l1_foundry()) + .script(&DEPLOY_GATEWAY_CTM.script(), forge_args.clone()) + .with_ffi() + .with_rpc_url(l1_rpc_url) + .with_calldata(&calldata) + .with_broadcast(); + + // Governor private key should not be needed for this script + forge = fill_forge_private_key( + forge, + config.get_wallets()?.deployer.as_ref(), + WalletOwner::Deployer, + )?; + check_the_balance(&forge).await?; + forge.run(shell)?; + + Ok(()) +} + +async fn gateway_governance_whitelisting( + shell: &Shell, + forge_args: ForgeScriptArgs, + config: &EcosystemConfig, + chain_config: &ChainConfig, + gateway_config: GatewayConfig, + l1_rpc_url: String, + with_broadcast: bool, +) -> anyhow::Result<()> { + let hash = call_script( + shell, + forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode("governanceRegisterGateway", ()) + .unwrap(), + config, + chain_config, + &config.get_wallets()?.governor, + l1_rpc_url.clone(), + with_broadcast, + ) + .await? + .governance_l2_tx_hash; + + // TOOD(EVM-931): adapt for more generic functionality from the rest of zkstack + if !with_broadcast { + // TODO(EVM-930): the path below relies explicitly on chain id 9. + shell.copy_file( + config.link_to_code.join("contracts/l1-contracts/broadcast/GatewayPreparation.s.sol/9/dry-run/932d9a4d-latest.json"), + config.link_to_code.join(GATEWAY_GOVERNANCE_TX_PATH1), + )?; + } + + println!( + "Gateway registered as a settlement layer with L2 hash: {}", + hash + ); + + let hash = call_script( + shell, + forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode( + "governanceWhitelistGatewayCTM", + (gateway_config.state_transition_proxy_addr, H256::random()), + ) + .unwrap(), + config, + chain_config, + &config.get_wallets()?.governor, + l1_rpc_url.clone(), + with_broadcast, + ) + .await? + .governance_l2_tx_hash; + + // TOOD(EVM-931): adapt for more generic functionality from the rest of zkstack + if !with_broadcast { + // TODO(EVM-930): the path below relies explicitly on chain id 9. + shell.copy_file( + config.link_to_code.join("contracts/l1-contracts/broadcast/GatewayPreparation.s.sol/9/dry-run/e518d36a-latest.json"), + config.link_to_code.join(GATEWAY_GOVERNANCE_TX_PATH1), + )?; + } + + // Just in case, the L2 tx may or may not fail depending on whether it was executed previously, + println!( + "Gateway STM whitelisted L2 hash: {}", + hex::encode(hash.as_bytes()) + ); + + let hash = call_script( + shell, + forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode("governanceSetCTMAssetHandler", H256::random()) + .unwrap(), + config, + chain_config, + &config.get_wallets()?.governor, + l1_rpc_url.clone(), + with_broadcast, + ) + .await? + .governance_l2_tx_hash; + + // TOOD(EVM-931): adapt for more generic functionality from the rest of zkstack + if !with_broadcast { + // TODO(EVM-930): the path below relies explicitly on chain id 9. + shell.copy_file( + config.link_to_code.join("contracts/l1-contracts/broadcast/GatewayPreparation.s.sol/9/dry-run/98b2aab7-latest.json"), + config.link_to_code.join(GATEWAY_GOVERNANCE_TX_PATH1), + )?; + } + + // Just in case, the L2 tx may or may not fail depending on whether it was executed previously, + println!( + "Gateway STM asset handler is set L2 hash: {}", + hex::encode(hash.as_bytes()) + ); + + let hash = call_script( + shell, + forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode( + "registerAssetIdInBridgehub", + (gateway_config.state_transition_proxy_addr, H256::random()), + ) + .unwrap(), + config, + chain_config, + &config.get_wallets()?.governor, + l1_rpc_url.clone(), + with_broadcast, + ) + .await? + .governance_l2_tx_hash; + + // TOOD(EVM-931): adapt for more generic functionality from the rest of zkstack + if !with_broadcast { + // TODO(EVM-930): the path below relies explicitly on chain id 9. + shell.copy_file( + config.link_to_code.join("contracts/l1-contracts/broadcast/GatewayPreparation.s.sol/9/dry-run/b620eb4c-latest.json"), + config.link_to_code.join(GATEWAY_GOVERNANCE_TX_PATH1), + )?; + } + + // Just in case, the L2 tx may or may not fail depending on whether it was executed previously, + println!( + "Asset Id is registered in L2 bridgehub. L2 hash: {}", + hex::encode(hash.as_bytes()) + ); + + Ok(()) +} + +#[allow(clippy::too_many_arguments)] +async fn call_script( + shell: &Shell, + forge_args: ForgeScriptArgs, + data: &Bytes, + config: &EcosystemConfig, + chain_config: &ChainConfig, + governor: &Wallet, + l1_rpc_url: String, + with_broadcast: bool, +) -> anyhow::Result { + let mut forge = Forge::new(&config.path_to_l1_foundry()) + .script(&GATEWAY_PREPARATION.script(), forge_args.clone()) + .with_ffi() + .with_rpc_url(l1_rpc_url) + .with_calldata(data); + if with_broadcast { + forge = forge.with_broadcast(); + } + + // Governor private key is required for this script + forge = fill_forge_private_key(forge, Some(governor), WalletOwner::Governor)?; + check_the_balance(&forge).await?; + forge.run(shell)?; + + GatewayPreparationOutput::read( + shell, + GATEWAY_PREPARATION.output(&chain_config.link_to_code), + ) +} diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/deploy_l2_contracts.rs b/zkstack_cli/crates/zkstack/src/commands/chain/deploy_l2_contracts.rs index 4164f9a05a2a..09732145d1db 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/deploy_l2_contracts.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/deploy_l2_contracts.rs @@ -284,7 +284,7 @@ async fn call_forge( signature: Option<&str>, ) -> anyhow::Result<()> { let input = DeployL2ContractsInput::new(chain_config, ecosystem_config.era_chain_id)?; - let foundry_contracts_path = chain_config.path_to_foundry(); + let foundry_contracts_path = chain_config.path_to_l1_foundry(); let secrets = chain_config.get_secrets_config()?; input.save( shell, diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/deploy_paymaster.rs b/zkstack_cli/crates/zkstack/src/commands/chain/deploy_paymaster.rs index 4bcfd6c08099..c6b48ca87856 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/deploy_paymaster.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/deploy_paymaster.rs @@ -34,7 +34,7 @@ pub async fn deploy_paymaster( broadcast: bool, ) -> anyhow::Result<()> { let input = DeployPaymasterInput::new(chain_config)?; - let foundry_contracts_path = chain_config.path_to_foundry(); + let foundry_contracts_path = chain_config.path_to_l1_foundry(); input.save( shell, DEPLOY_PAYMASTER_SCRIPT_PARAMS.input(&chain_config.link_to_code), diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/gateway_upgrade.rs b/zkstack_cli/crates/zkstack/src/commands/chain/gateway_upgrade.rs new file mode 100644 index 000000000000..8153bcfb0b7e --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/chain/gateway_upgrade.rs @@ -0,0 +1,505 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use anyhow::Context; +use clap::{Parser, ValueEnum}; +use common::{ + config::global_config, + forge::{Forge, ForgeScriptArgs}, +}; +use config::{ + forge_interface::{ + gateway_chain_upgrade::{ + input::GatewayChainUpgradeInput, output::GatewayChainUpgradeOutput, + }, + gateway_ecosystem_upgrade::output::GatewayEcosystemUpgradeOutput, + script_params::{GATEWAY_UPGRADE_CHAIN_PARAMS, GATEWAY_UPGRADE_ECOSYSTEM_PARAMS}, + }, + traits::{ReadConfig, ReadConfigWithBasePath, SaveConfig, SaveConfigWithBasePath}, + ChainConfig, EcosystemConfig, +}; +use ethers::{ + abi::{encode, parse_abi}, + contract::BaseContract, + utils::hex, +}; +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; +use strum::EnumIter; +use types::L1BatchCommitmentMode; +use xshell::Shell; +use zksync_basic_types::{H256, U256}; +use zksync_types::{web3::keccak256, Address, L2_NATIVE_TOKEN_VAULT_ADDRESS}; + +use crate::{ + accept_ownership::{ + admin_execute_upgrade, admin_schedule_upgrade, admin_update_validator, + set_da_validator_pair, + }, + messages::{MSG_CHAIN_NOT_INITIALIZED, MSG_L1_SECRETS_MUST_BE_PRESENTED}, + utils::forge::{fill_forge_private_key, WalletOwner}, +}; + +lazy_static! { + static ref ZK_CHAIN: BaseContract = + BaseContract::from(parse_abi(&["function getPriorityTreeStartIndex() public",]).unwrap(),); +} + +#[derive( + Debug, Serialize, Deserialize, Clone, Copy, ValueEnum, EnumIter, strum::Display, PartialEq, Eq, +)] +pub enum GatewayChainUpgradeStage { + // some config paaram + AdaptConfig, + + // Does not require admin, still needs to be done to update configs, etc + PrepareStage1, + + // Used to schedule an upgrade. + ScheduleStage1, + + // Should be executed after Stage1 of the governance upgrade + FinalizeStage1, + + // Mainly about changing configs + FinalizeStage2, + + // For tests in case a chain missed the correct window for the upgrade + // and needs to execute after Stage2 + KeepUpStage2, + + // Set L2 WETH address for chain in store + SetL2WETHForChain, +} + +#[derive(Debug, Serialize, Deserialize, Parser)] +pub struct GatewayUpgradeArgs { + /// All ethereum environment related arguments + #[clap(flatten)] + #[serde(flatten)] + pub forge_args: ForgeScriptArgs, + + chain_upgrade_stage: GatewayChainUpgradeStage, +} + +lazy_static! { + static ref GATEWAY_PREPARATION_INTERFACE: BaseContract = BaseContract::from( + parse_abi(&[ + "function startMigrateChainFromGateway(address chainAdmin,address accessControlRestriction,uint256 chainId) public", + "function finishMigrateChainFromGateway(uint256 migratingChainId,uint256 gatewayChainId,uint256 l2BatchNumber,uint256 l2MessageIndex,uint16 l2TxNumberInBatch,bytes memory message,bytes32[] memory merkleProof) public", + ]) + .unwrap(), + ); +} + +#[allow(unused)] +pub async fn run(args: GatewayUpgradeArgs, shell: &Shell) -> anyhow::Result<()> { + // TODO(EVM-927): this function does not work without the Gateway contracts. + anyhow::bail!("Gateway upgrade not supported yet!"); + + let ecosystem_config = EcosystemConfig::from_file(shell)?; + + let chain_name = global_config().chain_name.clone(); + let chain_config = ecosystem_config + .load_chain(chain_name) + .context(MSG_CHAIN_NOT_INITIALIZED)?; + + let l1_url = chain_config + .get_secrets_config()? + .l1 + .context(MSG_L1_SECRETS_MUST_BE_PRESENTED)? + .l1_rpc_url + .expose_str() + .to_string(); + + match args.chain_upgrade_stage { + GatewayChainUpgradeStage::AdaptConfig => adapt_config(shell, chain_config).await, + GatewayChainUpgradeStage::PrepareStage1 => { + prepare_stage1(shell, args, ecosystem_config, chain_config, l1_url).await + } + GatewayChainUpgradeStage::ScheduleStage1 => { + schedule_stage1(shell, args, ecosystem_config, chain_config, l1_url).await + } + GatewayChainUpgradeStage::FinalizeStage1 => { + finalize_stage1(shell, args, ecosystem_config, chain_config, l1_url).await + } + GatewayChainUpgradeStage::FinalizeStage2 => { + finalize_stage2(shell, ecosystem_config, chain_config).await + } + GatewayChainUpgradeStage::KeepUpStage2 => { + panic!("Not supported"); + } + GatewayChainUpgradeStage::SetL2WETHForChain => { + set_weth_for_chain(shell, args, ecosystem_config, chain_config, l1_url).await + } + } +} + +fn encode_ntv_asset_id(l1_chain_id: U256, addr: Address) -> H256 { + let encoded_data = encode(&[ + ethers::abi::Token::Uint(l1_chain_id), + ethers::abi::Token::Address(L2_NATIVE_TOKEN_VAULT_ADDRESS), + ethers::abi::Token::Address(addr), + ]); + + H256(keccak256(&encoded_data)) +} + +async fn adapt_config(shell: &Shell, chain_config: ChainConfig) -> anyhow::Result<()> { + println!("Adapting config"); + let mut contracts_config = chain_config.get_contracts_config()?; + let genesis_config = chain_config.get_genesis_config()?; + + contracts_config.l2.legacy_shared_bridge_addr = contracts_config.bridges.shared.l2_address; + contracts_config.l1.base_token_asset_id = Some(encode_ntv_asset_id( + genesis_config.l1_chain_id.0.into(), + contracts_config.l1.base_token_addr, + )); + + contracts_config.save_with_base_path(shell, &chain_config.configs)?; + println!("Done"); + + Ok(()) +} + +async fn prepare_stage1( + shell: &Shell, + args: GatewayUpgradeArgs, + ecosystem_config: EcosystemConfig, + chain_config: ChainConfig, + l1_url: String, +) -> anyhow::Result<()> { + let chain_upgrade_config_path = + GATEWAY_UPGRADE_CHAIN_PARAMS.input(&ecosystem_config.link_to_code); + + let gateway_upgrade_input = GatewayChainUpgradeInput::new(&chain_config); + gateway_upgrade_input.save(shell, chain_upgrade_config_path.clone())?; + + let mut forge = Forge::new(&ecosystem_config.path_to_l1_foundry()) + .script( + &GATEWAY_UPGRADE_CHAIN_PARAMS.script(), + args.forge_args.clone(), + ) + .with_ffi() + .with_rpc_url(l1_url) + .with_slow() + .with_broadcast(); + + forge = fill_forge_private_key( + forge, + Some(&chain_config.get_wallets_config()?.governor), + WalletOwner::Governor, + )?; + + println!("Preparing the chain for the upgrade!"); + + forge.run(shell)?; + + println!("done!"); + + let chain_output = GatewayChainUpgradeOutput::read( + shell, + GATEWAY_UPGRADE_CHAIN_PARAMS.output(&ecosystem_config.link_to_code), + )?; + + let gateway_ecosystem_preparation_output = + GatewayEcosystemUpgradeOutput::read_with_base_path(shell, ecosystem_config.config)?; + + // No need to save it, we have enough for now + + let mut contracts_config = chain_config.get_contracts_config()?; + + contracts_config + .ecosystem_contracts + .stm_deployment_tracker_proxy_addr = Some( + gateway_ecosystem_preparation_output + .deployed_addresses + .bridgehub + .ctm_deployment_tracker_proxy_addr, + ); + // This is force deployment data for creating new contracts, not really relevant here tbh, + contracts_config.ecosystem_contracts.force_deployments_data = Some(hex::encode( + &gateway_ecosystem_preparation_output + .contracts_config + .force_deployments_data + .0, + )); + contracts_config.ecosystem_contracts.native_token_vault_addr = Some( + gateway_ecosystem_preparation_output + .deployed_addresses + .native_token_vault_addr, + ); + contracts_config + .ecosystem_contracts + .l1_bytecodes_supplier_addr = Some( + gateway_ecosystem_preparation_output + .deployed_addresses + .l1_bytecodes_supplier_addr, + ); + contracts_config.l1.access_control_restriction_addr = + Some(chain_output.access_control_restriction); + contracts_config.l1.chain_admin_addr = chain_output.chain_admin_addr; + + contracts_config.l1.rollup_l1_da_validator_addr = Some( + gateway_ecosystem_preparation_output + .deployed_addresses + .rollup_l1_da_validator_addr, + ); + contracts_config.l1.no_da_validium_l1_validator_addr = Some( + gateway_ecosystem_preparation_output + .deployed_addresses + .validium_l1_da_validator_addr, + ); + + let validum = chain_config + .get_genesis_config()? + .l1_batch_commit_data_generator_mode + == L1BatchCommitmentMode::Validium; + + // We do not use chain output because IMHO we should delete it altogether from there + contracts_config.l2.da_validator_addr = if !validum { + Some( + gateway_ecosystem_preparation_output + .contracts_config + .expected_rollup_l2_da_validator, + ) + } else { + Some( + gateway_ecosystem_preparation_output + .contracts_config + .expected_validium_l2_da_validator, + ) + }; + contracts_config.l2.l2_native_token_vault_proxy_addr = Some(L2_NATIVE_TOKEN_VAULT_ADDRESS); + contracts_config.l2.legacy_shared_bridge_addr = contracts_config.bridges.shared.l2_address; + + contracts_config.save_with_base_path(shell, chain_config.configs)?; + + Ok(()) +} + +const NEW_PROTOCOL_VERSION: u64 = 0x1b00000000; + +async fn schedule_stage1( + shell: &Shell, + args: GatewayUpgradeArgs, + ecosystem_config: EcosystemConfig, + chain_config: ChainConfig, + l1_url: String, +) -> anyhow::Result<()> { + println!("Schedule stage1 of the upgrade!!"); + + admin_schedule_upgrade( + shell, + &ecosystem_config, + &chain_config.get_contracts_config()?, + // For now it is hardcoded both in scripts and here + U256::from(NEW_PROTOCOL_VERSION), + // We only do instant upgrades for now + U256::zero(), + &chain_config.get_wallets_config()?.governor, + &args.forge_args, + l1_url.clone(), + ) + .await?; + + println!("done!"); + + Ok(()) +} + +async fn finalize_stage1( + shell: &Shell, + args: GatewayUpgradeArgs, + ecosystem_config: EcosystemConfig, + chain_config: ChainConfig, + l1_url: String, +) -> anyhow::Result<()> { + println!("Finalizing stage1 of chain upgrade!"); + + let mut contracts_config = chain_config.get_contracts_config()?; + let gateway_ecosystem_preparation_output = + GatewayEcosystemUpgradeOutput::read_with_base_path(shell, &ecosystem_config.config)?; + + let old_validator_timelock = contracts_config.l1.validator_timelock_addr; + let new_validator_timelock = gateway_ecosystem_preparation_output + .deployed_addresses + .validator_timelock_addr; + + let validators = [ + chain_config.get_wallets_config()?.operator.address, + chain_config.get_wallets_config()?.blob_operator.address, + ]; + + println!("Setting new validators!"); + for val in validators { + admin_update_validator( + shell, + &ecosystem_config, + &chain_config, + old_validator_timelock, + val, + false, + &chain_config.get_wallets_config()?.governor, + &args.forge_args, + l1_url.clone(), + ) + .await?; + + admin_update_validator( + shell, + &ecosystem_config, + &chain_config, + new_validator_timelock, + val, + true, + &chain_config.get_wallets_config()?.governor, + &args.forge_args, + l1_url.clone(), + ) + .await?; + } + + println!("Setting new validators done!"); + + contracts_config.l1.validator_timelock_addr = gateway_ecosystem_preparation_output + .deployed_addresses + .validator_timelock_addr; + + admin_execute_upgrade( + shell, + &ecosystem_config, + &chain_config.get_contracts_config()?, + &chain_config.get_wallets_config()?.governor, + gateway_ecosystem_preparation_output + .chain_upgrade_diamond_cut + .0, + &args.forge_args, + l1_url.clone(), + ) + .await?; + + let l1_da_validator_contract = if chain_config + .get_genesis_config()? + .l1_batch_commit_data_generator_mode + == L1BatchCommitmentMode::Rollup + { + ecosystem_config + .get_contracts_config()? + .l1 + .rollup_l1_da_validator_addr + } else { + ecosystem_config + .get_contracts_config()? + .l1 + .no_da_validium_l1_validator_addr + } + .context("l1 da validator")?; + + set_da_validator_pair( + shell, + &ecosystem_config, + contracts_config.l1.chain_admin_addr, + &chain_config.get_wallets_config()?.governor, + contracts_config.l1.diamond_proxy_addr, + l1_da_validator_contract, + contracts_config + .l2 + .da_validator_addr + .context("l2_da_validator_addr")?, + &args.forge_args, + l1_url, + ) + .await?; + + contracts_config.save_with_base_path(shell, &chain_config.configs)?; + + println!("done!"); + + Ok(()) +} + +async fn finalize_stage2( + shell: &Shell, + ecosystem_config: EcosystemConfig, + chain_config: ChainConfig, +) -> anyhow::Result<()> { + println!("Finalizing stage2 for the chain! (just updating configs)"); + + let ecosystem_config = ecosystem_config.get_contracts_config()?; + + let mut contracts_config = chain_config.get_contracts_config()?; + contracts_config.bridges.l1_nullifier_addr = Some(contracts_config.bridges.shared.l1_address); + contracts_config.bridges.shared.l1_address = ecosystem_config.bridges.shared.l1_address; + contracts_config.bridges.shared.l2_address = + Some(zksync_system_constants::L2_ASSET_ROUTER_ADDRESS); + contracts_config.save_with_base_path(shell, &chain_config.configs)?; + + println!("done!"); + + Ok(()) +} + +async fn set_weth_for_chain( + shell: &Shell, + args: GatewayUpgradeArgs, + ecosystem_config: EcosystemConfig, + chain_config: ChainConfig, + l1_url: String, +) -> anyhow::Result<()> { + println!("Adding l2 weth to store!"); + + let forge_args = args.forge_args.clone(); + let l1_rpc_url = l1_url; + + let previous_output = GatewayEcosystemUpgradeOutput::read( + shell, + GATEWAY_UPGRADE_ECOSYSTEM_PARAMS.output(&ecosystem_config.link_to_code), + )?; + let contract: BaseContract = BaseContract::from( + parse_abi(&[ + "function addL2WethToStore(address storeAddress, address chainAdmin, uint256 chainId, address l2WBaseToken) public", + ]) + .unwrap(), + ); + let contracts_config = chain_config.get_contracts_config()?; + let calldata = contract + .encode( + "addL2WethToStore", + ( + previous_output + .deployed_addresses + .l2_wrapped_base_token_store_addr, + ecosystem_config + .get_contracts_config() + .expect("get_contracts_config()") + .l1 + .chain_admin_addr, + chain_config.chain_id.as_u64(), + contracts_config + .l2 + .predeployed_l2_wrapped_base_token_address + .expect("No predeployed_l2_wrapped_base_token_address"), + ), + ) + .unwrap(); + + let mut forge = Forge::new(&ecosystem_config.path_to_l1_foundry()) + .script( + &GATEWAY_UPGRADE_ECOSYSTEM_PARAMS.script(), + forge_args.clone(), + ) + .with_ffi() + .with_rpc_url(l1_rpc_url) + .with_slow() + .with_gas_limit(1_000_000_000_000) + .with_calldata(&calldata) + .with_broadcast(); + + forge = fill_forge_private_key( + forge, + Some(&ecosystem_config.get_wallets()?.governor), + WalletOwner::Governor, + )?; + forge.run(shell)?; + + Ok(()) +} diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/genesis/server.rs b/zkstack_cli/crates/zkstack/src/commands/chain/genesis/server.rs index 50a74b7ea9e4..090792e8007a 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/genesis/server.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/genesis/server.rs @@ -40,6 +40,7 @@ pub fn run_server_genesis(chain_config: &ChainConfig, shell: &Shell) -> anyhow:: GeneralConfig::get_path_with_base_path(&chain_config.configs), SecretsConfig::get_path_with_base_path(&chain_config.configs), ContractsConfig::get_path_with_base_path(&chain_config.configs), + None, vec![], ) .context(MSG_FAILED_TO_RUN_SERVER_ERR) diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/migrate_from_gateway.rs b/zkstack_cli/crates/zkstack/src/commands/chain/migrate_from_gateway.rs new file mode 100644 index 000000000000..71521e62c3e6 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/chain/migrate_from_gateway.rs @@ -0,0 +1,300 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use anyhow::Context; +use clap::Parser; +use common::{ + config::global_config, + forge::{Forge, ForgeScriptArgs}, + wallets::Wallet, + zks_provider::ZKSProvider, +}; +use config::{ + forge_interface::{ + gateway_preparation::{input::GatewayPreparationConfig, output::GatewayPreparationOutput}, + script_params::GATEWAY_PREPARATION, + }, + traits::{ReadConfig, SaveConfig, SaveConfigWithBasePath}, + EcosystemConfig, +}; +use ethers::{ + abi::parse_abi, + contract::BaseContract, + providers::{Http, Middleware, Provider}, + types::Bytes, + utils::hex, +}; +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; +use types::L1BatchCommitmentMode; +use xshell::Shell; +use zksync_basic_types::{ + pubdata_da::PubdataSendingMode, settlement::SettlementMode, H256, U256, U64, +}; +use zksync_types::L2ChainId; +use zksync_web3_decl::client::{Client, L2}; + +use crate::{ + messages::{MSG_CHAIN_NOT_INITIALIZED, MSG_L1_SECRETS_MUST_BE_PRESENTED}, + utils::forge::{check_the_balance, fill_forge_private_key, WalletOwner}, +}; + +#[derive(Debug, Serialize, Deserialize, Parser)] +pub struct MigrateFromGatewayArgs { + /// All ethereum environment related arguments + #[clap(flatten)] + #[serde(flatten)] + pub forge_args: ForgeScriptArgs, + + #[clap(long)] + pub gateway_chain_name: String, +} + +lazy_static! { + static ref GATEWAY_PREPARATION_INTERFACE: BaseContract = BaseContract::from( + parse_abi(&[ + "function startMigrateChainFromGateway(address chainAdmin,address accessControlRestriction,address l2ChainAdmin,uint256 chainId) public", + "function finishMigrateChainFromGateway(uint256 migratingChainId,uint256 gatewayChainId,uint256 l2BatchNumber,uint256 l2MessageIndex,uint16 l2TxNumberInBatch,bytes memory message,bytes32[] memory merkleProof) public", + ]) + .unwrap(), + ); +} + +#[allow(unused)] +pub async fn run(args: MigrateFromGatewayArgs, shell: &Shell) -> anyhow::Result<()> { + // TODO(EVM-927): this function does not work without the Gateway contracts. + anyhow::bail!("Gateway upgrade not supported yet!"); + + let ecosystem_config = EcosystemConfig::from_file(shell)?; + + let chain_name = global_config().chain_name.clone(); + let chain_config = ecosystem_config + .load_chain(chain_name) + .context(MSG_CHAIN_NOT_INITIALIZED)?; + + let gateway_chain_config = ecosystem_config + .load_chain(Some(args.gateway_chain_name.clone())) + .context("Gateway not present")?; + let gateway_chain_id = gateway_chain_config.chain_id.as_u64(); + let gateway_gateway_config = gateway_chain_config + .get_gateway_config() + .context("Gateway config not present")?; + + let l1_url = chain_config + .get_secrets_config()? + .l1 + .context(MSG_L1_SECRETS_MUST_BE_PRESENTED)? + .l1_rpc_url + .expose_str() + .to_string(); + + let genesis_config = chain_config.get_genesis_config()?; + + let is_rollup = matches!( + genesis_config.l1_batch_commit_data_generator_mode, + L1BatchCommitmentMode::Rollup + ); + + let preparation_config_path = GATEWAY_PREPARATION.input(&ecosystem_config.link_to_code); + let preparation_config = GatewayPreparationConfig::new( + &gateway_chain_config, + &gateway_chain_config.get_contracts_config()?, + &ecosystem_config.get_contracts_config()?, + &gateway_gateway_config, + )?; + preparation_config.save(shell, preparation_config_path)?; + + let chain_contracts_config = chain_config.get_contracts_config().unwrap(); + let mut gateway_chain_chain_config = chain_config.get_gateway_chain_config().unwrap(); + let chain_admin_addr = chain_contracts_config.l1.chain_admin_addr; + let chain_access_control_restriction = + chain_contracts_config.l1.access_control_restriction_addr; + + println!("Migrating the chain to L1..."); + let hash = call_script( + shell, + args.forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode( + "startMigrateChainFromGateway", + ( + chain_admin_addr, + chain_access_control_restriction.context("chain_access_control_restriction")?, + gateway_chain_chain_config + .chain_admin_addr + .context("l2 chain admin missing")?, + U256::from(chain_config.chain_id.as_u64()), + ), + ) + .unwrap(), + &ecosystem_config, + &chain_config.get_wallets_config()?.governor, + l1_url.clone(), + ) + .await?; + + let gateway_provider = Provider::::try_from( + gateway_chain_config + .get_general_config() + .unwrap() + .api_config + .unwrap() + .web3_json_rpc + .http_url, + )?; + + let client: Client = Client::http( + gateway_chain_config + .get_general_config() + .unwrap() + .api_config + .unwrap() + .web3_json_rpc + .http_url + .parse() + .unwrap(), + )? + .for_network(L2::from(L2ChainId::new(gateway_chain_id).unwrap())) + .build(); + + if hash == H256::zero() { + println!("Chain already migrated!"); + } else { + println!("Migration started! Migration hash: {}", hex::encode(hash)); + await_for_tx_to_complete(&gateway_provider, hash).await?; + await_for_withdrawal_to_finalize(&client, hash).await?; + } + // FIXME: this is a temporary hack to make sure that the withdrawal is processed. + tokio::time::sleep(tokio::time::Duration::from_millis(60000)).await; + + let params = client.get_finalize_withdrawal_params(hash, 0).await?; + + call_script( + shell, + args.forge_args, + &GATEWAY_PREPARATION_INTERFACE + .encode( + "finishMigrateChainFromGateway", + ( + U256::from(chain_config.chain_id.as_u64()), + U256::from(gateway_chain_id), + U256::from(params.l2_batch_number.0[0]), + U256::from(params.l2_message_index.0[0]), + U256::from(params.l2_tx_number_in_block.0[0]), + params.message, + params.proof.proof, + ), + ) + .unwrap(), + &ecosystem_config, + &chain_config.get_wallets_config()?.governor, + l1_url.clone(), + ) + .await?; + + gateway_chain_chain_config.gateway_chain_id = 0u64.into(); + gateway_chain_chain_config.save_with_base_path(shell, chain_config.configs.clone())?; + + let mut general_config = chain_config.get_general_config().unwrap(); + + let eth_config = general_config.eth.as_mut().context("eth")?; + + eth_config + .gas_adjuster + .as_mut() + .expect("gas_adjuster") + .settlement_mode = SettlementMode::SettlesToL1; + if is_rollup { + // For rollups, new type of commitment should be used, but + // not for validium. + eth_config + .sender + .as_mut() + .expect("sender") + .pubdata_sending_mode = PubdataSendingMode::Blobs; + } + eth_config + .sender + .as_mut() + .context("sender")? + .wait_confirmations = Some(0); + // Undoing what was changed during migration to gateway. + // TODO(EVM-925): maybe remove this logic. + eth_config + .sender + .as_mut() + .expect("sender") + .max_aggregated_tx_gas = 15000000; + eth_config + .sender + .as_mut() + .expect("sender") + .max_eth_tx_data_size = 120_000; + + general_config.save_with_base_path(shell, chain_config.configs.clone())?; + Ok(()) +} + +async fn await_for_tx_to_complete( + gateway_provider: &Provider, + hash: H256, +) -> anyhow::Result<()> { + println!("Waiting for transaction to complete..."); + while gateway_provider + .get_transaction_receipt(hash) + .await? + .is_none() + { + tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; + } + + // We do not handle network errors + let receipt = gateway_provider + .get_transaction_receipt(hash) + .await? + .unwrap(); + + if receipt.status == Some(U64::from(1)) { + println!("Transaction completed successfully!"); + } else { + panic!("Transaction failed!"); + } + + Ok(()) +} + +async fn await_for_withdrawal_to_finalize( + gateway_provider: &Client, + hash: H256, +) -> anyhow::Result<()> { + println!("Waiting for withdrawal to finalize..."); + while gateway_provider.get_withdrawal_log(hash, 0).await.is_err() { + println!("Waiting for withdrawal to finalize..."); + tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; + } + Ok(()) +} + +async fn call_script( + shell: &Shell, + forge_args: ForgeScriptArgs, + data: &Bytes, + config: &EcosystemConfig, + governor: &Wallet, + rpc_url: String, +) -> anyhow::Result { + let mut forge = Forge::new(&config.path_to_l1_foundry()) + .script(&GATEWAY_PREPARATION.script(), forge_args.clone()) + .with_ffi() + .with_rpc_url(rpc_url) + .with_broadcast() + .with_calldata(data); + + // Governor private key is required for this script + forge = fill_forge_private_key(forge, Some(governor), WalletOwner::Governor)?; + check_the_balance(&forge).await?; + forge.run(shell)?; + + let gateway_preparation_script_output = + GatewayPreparationOutput::read(shell, GATEWAY_PREPARATION.output(&config.link_to_code))?; + + Ok(gateway_preparation_script_output.governance_l2_tx_hash) +} diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/migrate_to_gateway.rs b/zkstack_cli/crates/zkstack/src/commands/chain/migrate_to_gateway.rs new file mode 100644 index 000000000000..e5202c570183 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/chain/migrate_to_gateway.rs @@ -0,0 +1,479 @@ +use anyhow::Context; +use clap::Parser; +use common::{ + config::global_config, + forge::{Forge, ForgeScriptArgs}, + wallets::Wallet, +}; +use config::{ + forge_interface::{ + gateway_preparation::{input::GatewayPreparationConfig, output::GatewayPreparationOutput}, + script_params::GATEWAY_PREPARATION, + }, + traits::{ReadConfig, SaveConfig, SaveConfigWithBasePath}, + EcosystemConfig, +}; +use ethers::{ + abi::parse_abi, + contract::BaseContract, + providers::{Http, Middleware, Provider}, + types::Bytes, + utils::hex, +}; +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; +use types::L1BatchCommitmentMode; +use xshell::Shell; +use zksync_basic_types::{ + pubdata_da::PubdataSendingMode, settlement::SettlementMode, Address, H256, U256, U64, +}; +use zksync_config::configs::gateway::GatewayChainConfig; +use zksync_system_constants::L2_BRIDGEHUB_ADDRESS; + +use crate::{ + messages::{MSG_CHAIN_NOT_INITIALIZED, MSG_L1_SECRETS_MUST_BE_PRESENTED}, + utils::forge::{check_the_balance, fill_forge_private_key, WalletOwner}, +}; + +#[derive(Debug, Serialize, Deserialize, Parser)] +pub struct MigrateToGatewayArgs { + /// All ethereum environment related arguments + #[clap(flatten)] + #[serde(flatten)] + pub forge_args: ForgeScriptArgs, + + #[clap(long)] + pub gateway_chain_name: String, +} + +lazy_static! { + static ref GATEWAY_PREPARATION_INTERFACE: BaseContract = BaseContract::from( + parse_abi(&[ + "function migrateChainToGateway(address chainAdmin,address l2ChainAdmin,address accessControlRestriction,uint256 chainId) public", + "function setDAValidatorPair(address chainAdmin,address accessControlRestriction,uint256 chainId,address l1DAValidator,address l2DAValidator,address chainDiamondProxyOnGateway,address chainAdminOnGateway)", + "function supplyGatewayWallet(address addr, uint256 addr) public", + "function enableValidator(address chainAdmin,address accessControlRestriction,uint256 chainId,address validatorAddress,address gatewayValidatorTimelock,address chainAdminOnGateway) public", + "function grantWhitelist(address filtererProxy, address[] memory addr) public", + "function deployL2ChainAdmin() public" + ]) + .unwrap(), + ); + + static ref BRIDGEHUB_INTERFACE: BaseContract = BaseContract::from( + parse_abi(&[ + "function getHyperchain(uint256 chainId) public returns (address)" + ]) + .unwrap(), + ); +} + +// TODO(EVM-927): merge gateway contracts +#[allow(unused)] +pub async fn run(args: MigrateToGatewayArgs, shell: &Shell) -> anyhow::Result<()> { + // TODO(EVM-927): this function does not work without the Gateway contracts. + anyhow::bail!("Gateway upgrade not supported yet!"); + + let ecosystem_config = EcosystemConfig::from_file(shell)?; + + let chain_name = global_config().chain_name.clone(); + let chain_config = ecosystem_config + .load_chain(chain_name) + .context(MSG_CHAIN_NOT_INITIALIZED)?; + + let gateway_chain_config = ecosystem_config + .load_chain(Some(args.gateway_chain_name.clone())) + .context("Gateway not present")?; + let gateway_chain_id = gateway_chain_config.chain_id.as_u64(); + let gateway_gateway_config = gateway_chain_config + .get_gateway_config() + .context("Gateway config not present")?; + + let l1_url = chain_config + .get_secrets_config()? + .l1 + .context(MSG_L1_SECRETS_MUST_BE_PRESENTED)? + .l1_rpc_url + .expose_str() + .to_string(); + + let genesis_config = chain_config.get_genesis_config()?; + + let preparation_config_path = GATEWAY_PREPARATION.input(&ecosystem_config.link_to_code); + let preparation_config = GatewayPreparationConfig::new( + &gateway_chain_config, + &gateway_chain_config.get_contracts_config()?, + &ecosystem_config.get_contracts_config()?, + &gateway_gateway_config, + )?; + preparation_config.save(shell, preparation_config_path)?; + + let chain_contracts_config = chain_config.get_contracts_config().unwrap(); + let chain_admin_addr = chain_contracts_config.l1.chain_admin_addr; + let chain_access_control_restriction = chain_contracts_config + .l1 + .access_control_restriction_addr + .context("chain_access_control_restriction")?; + + println!("Whitelisting the chains' addresseses..."); + call_script( + shell, + args.forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode( + "grantWhitelist", + ( + gateway_chain_config + .get_contracts_config()? + .l1 + .transaction_filterer_addr + .context("transaction_filterer_addr")?, + vec![ + chain_config.get_wallets_config()?.governor.address, + chain_config.get_contracts_config()?.l1.chain_admin_addr, + ], + ), + ) + .unwrap(), + &ecosystem_config, + &gateway_chain_config.get_wallets_config()?.governor, + l1_url.clone(), + ) + .await?; + + println!("Migrating the chain to the Gateway..."); + + let l2_chain_admin = call_script( + shell, + args.forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode("deployL2ChainAdmin", ()) + .unwrap(), + &ecosystem_config, + &chain_config.get_wallets_config()?.governor, + l1_url.clone(), + ) + .await? + .l2_chain_admin_address; + println!( + "L2 chain admin deployed! Its address: {:#?}", + l2_chain_admin + ); + + let hash = call_script( + shell, + args.forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode( + "migrateChainToGateway", + ( + chain_admin_addr, + // TODO(EVM-746): Use L2-based chain admin contract + l2_chain_admin, + chain_access_control_restriction, + U256::from(chain_config.chain_id.as_u64()), + ), + ) + .unwrap(), + &ecosystem_config, + &chain_config.get_wallets_config()?.governor, + l1_url.clone(), + ) + .await? + .governance_l2_tx_hash; + + let gateway_provider = Provider::::try_from( + gateway_chain_config + .get_general_config() + .unwrap() + .api_config + .unwrap() + .web3_json_rpc + .http_url, + )?; + + if hash == H256::zero() { + println!("Chain already migrated!"); + } else { + println!("Migration started! Migration hash: {}", hex::encode(hash)); + await_for_tx_to_complete(&gateway_provider, hash).await?; + } + + // After the migration is done, there are a few things left to do: + // Let's grab the new diamond proxy address + + // TODO(EVM-929): maybe move to using a precalculated address, just like for EN + let chain_id = U256::from(chain_config.chain_id.as_u64()); + let contract = BRIDGEHUB_INTERFACE + .clone() + .into_contract(L2_BRIDGEHUB_ADDRESS, gateway_provider); + + let method = contract.method::("getHyperchain", chain_id)?; + + let new_diamond_proxy_address = method.call().await?; + + println!( + "New diamond proxy address: {}", + hex::encode(new_diamond_proxy_address.as_bytes()) + ); + + let chain_contracts_config = chain_config.get_contracts_config().unwrap(); + + let is_rollup = matches!( + genesis_config.l1_batch_commit_data_generator_mode, + L1BatchCommitmentMode::Rollup + ); + + let gateway_da_validator_address = if is_rollup { + gateway_gateway_config.relayed_sl_da_validator + } else { + gateway_gateway_config.validium_da_validator + }; + + println!("Setting DA validator pair..."); + let hash = call_script( + shell, + args.forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode( + "setDAValidatorPair", + ( + chain_admin_addr, + chain_access_control_restriction, + U256::from(chain_config.chain_id.as_u64()), + gateway_da_validator_address, + chain_contracts_config + .l2 + .da_validator_addr + .context("da_validator_addr")?, + new_diamond_proxy_address, + l2_chain_admin, + ), + ) + .unwrap(), + &ecosystem_config, + &chain_config.get_wallets_config()?.governor, + l1_url.clone(), + ) + .await? + .governance_l2_tx_hash; + println!( + "DA validator pair set! Hash: {}", + hex::encode(hash.as_bytes()) + ); + + let chain_secrets_config = chain_config.get_wallets_config().unwrap(); + + println!("Enabling validators..."); + let hash = call_script( + shell, + args.forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode( + "enableValidator", + ( + chain_admin_addr, + chain_access_control_restriction, + U256::from(chain_config.chain_id.as_u64()), + chain_secrets_config.blob_operator.address, + gateway_gateway_config.validator_timelock_addr, + l2_chain_admin, + ), + ) + .unwrap(), + &ecosystem_config, + &chain_config.get_wallets_config()?.governor, + l1_url.clone(), + ) + .await? + .governance_l2_tx_hash; + println!( + "blob_operator enabled! Hash: {}", + hex::encode(hash.as_bytes()) + ); + + let hash = call_script( + shell, + args.forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode( + "supplyGatewayWallet", + ( + chain_secrets_config.blob_operator.address, + U256::from_dec_str("10000000000000000000").unwrap(), + ), + ) + .unwrap(), + &ecosystem_config, + &chain_config.get_wallets_config()?.governor, + l1_url.clone(), + ) + .await? + .governance_l2_tx_hash; + println!( + "blob_operator supplied with 10 ETH! Hash: {}", + hex::encode(hash.as_bytes()) + ); + + let hash = call_script( + shell, + args.forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode( + "enableValidator", + ( + chain_admin_addr, + chain_access_control_restriction, + U256::from(chain_config.chain_id.as_u64()), + chain_secrets_config.operator.address, + gateway_gateway_config.validator_timelock_addr, + l2_chain_admin, + ), + ) + .unwrap(), + &ecosystem_config, + &chain_config.get_wallets_config()?.governor, + l1_url.clone(), + ) + .await? + .governance_l2_tx_hash; + println!("operator enabled! Hash: {}", hex::encode(hash.as_bytes())); + + let hash = call_script( + shell, + args.forge_args.clone(), + &GATEWAY_PREPARATION_INTERFACE + .encode( + "supplyGatewayWallet", + ( + chain_secrets_config.operator.address, + U256::from_dec_str("10000000000000000000").unwrap(), + ), + ) + .unwrap(), + &ecosystem_config, + &chain_config.get_wallets_config()?.governor, + l1_url.clone(), + ) + .await? + .governance_l2_tx_hash; + println!( + "operator supplied with 10 ETH! Hash: {}", + hex::encode(hash.as_bytes()) + ); + + let gateway_url = gateway_chain_config + .get_general_config() + .unwrap() + .api_config + .unwrap() + .web3_json_rpc + .http_url + .clone(); + + let mut chain_secrets_config = chain_config.get_secrets_config().unwrap(); + chain_secrets_config.l1.as_mut().unwrap().gateway_rpc_url = + Some(url::Url::parse(&gateway_url).unwrap().into()); + chain_secrets_config.save_with_base_path(shell, chain_config.configs.clone())?; + + let gateway_chain_config = GatewayChainConfig::from_gateway_and_chain_data( + &gateway_gateway_config, + new_diamond_proxy_address, + l2_chain_admin, + gateway_chain_id.into(), + ); + gateway_chain_config.save_with_base_path(shell, chain_config.configs.clone())?; + + let mut general_config = chain_config.get_general_config().unwrap(); + + let eth_config = general_config.eth.as_mut().context("eth")?; + + eth_config + .gas_adjuster + .as_mut() + .expect("gas_adjuster") + .settlement_mode = SettlementMode::Gateway; + if is_rollup { + // For rollups, new type of commitment should be used, but + // not for validium. + eth_config + .sender + .as_mut() + .expect("sender") + .pubdata_sending_mode = PubdataSendingMode::RelayedL2Calldata; + } + eth_config + .sender + .as_mut() + .context("sender")? + .wait_confirmations = Some(0); + // TODO(EVM-925): the number below may not always work, especially for large prices on + // top of Gateway. This field would have to be either not used on GW or transformed into u64. + eth_config + .sender + .as_mut() + .expect("sender") + .max_aggregated_tx_gas = 4294967295; + eth_config + .sender + .as_mut() + .expect("sender") + .max_eth_tx_data_size = 550_000; + + general_config.save_with_base_path(shell, chain_config.configs.clone())?; + + Ok(()) +} + +async fn await_for_tx_to_complete( + gateway_provider: &Provider, + hash: H256, +) -> anyhow::Result<()> { + println!("Waiting for transaction to complete..."); + while gateway_provider + .get_transaction_receipt(hash) + .await? + .is_none() + { + tokio::time::sleep(tokio::time::Duration::from_millis(200)).await; + } + + // We do not handle network errors + let receipt = gateway_provider + .get_transaction_receipt(hash) + .await? + .unwrap(); + + if receipt.status == Some(U64::from(1)) { + println!("Transaction completed successfully!"); + } else { + panic!("Transaction failed!"); + } + + Ok(()) +} + +async fn call_script( + shell: &Shell, + forge_args: ForgeScriptArgs, + data: &Bytes, + config: &EcosystemConfig, + governor: &Wallet, + l1_rpc_url: String, +) -> anyhow::Result { + let mut forge = Forge::new(&config.path_to_l1_foundry()) + .script(&GATEWAY_PREPARATION.script(), forge_args.clone()) + .with_ffi() + .with_rpc_url(l1_rpc_url) + .with_broadcast() + .with_calldata(data); + + // Governor private key is required for this script + forge = fill_forge_private_key(forge, Some(governor), WalletOwner::Governor)?; + check_the_balance(&forge).await?; + forge.run(shell)?; + + let gateway_preparation_script_output = + GatewayPreparationOutput::read(shell, GATEWAY_PREPARATION.output(&config.link_to_code))?; + + Ok(gateway_preparation_script_output) +} diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/mod.rs b/zkstack_cli/crates/zkstack/src/commands/chain/mod.rs index c7d31ddf7dbc..474f1c779016 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/mod.rs @@ -14,12 +14,16 @@ mod accept_chain_ownership; pub(crate) mod args; mod build_transactions; mod common; +mod convert_to_gateway; mod create; pub mod deploy_l2_contracts; pub mod deploy_paymaster; mod enable_evm_emulator; +mod gateway_upgrade; pub mod genesis; pub mod init; +mod migrate_from_gateway; +mod migrate_to_gateway; pub mod register_chain; mod set_token_multiplier_setter; mod setup_legacy_bridge; diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/register_chain.rs b/zkstack_cli/crates/zkstack/src/commands/chain/register_chain.rs index 42b3bbd59c71..6269b0af0ea9 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/register_chain.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/register_chain.rs @@ -69,7 +69,7 @@ pub async fn register_chain( let deploy_config = RegisterChainL1Config::new(chain_config, contracts)?; deploy_config.save(shell, deploy_config_path)?; - let mut forge = Forge::new(&config.path_to_foundry()) + let mut forge = Forge::new(&config.path_to_l1_foundry()) .script(®ISTER_CHAIN_SCRIPT_PARAMS.script(), forge_args.clone()) .with_ffi() .with_rpc_url(l1_rpc_url); diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/set_token_multiplier_setter.rs b/zkstack_cli/crates/zkstack/src/commands/chain/set_token_multiplier_setter.rs index 326aa393f8f2..bff3cfe467b5 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/set_token_multiplier_setter.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/set_token_multiplier_setter.rs @@ -91,7 +91,7 @@ pub async fn set_token_multiplier_setter( (chain_admin_address, target_address), ) .unwrap(); - let foundry_contracts_path = ecosystem_config.path_to_foundry(); + let foundry_contracts_path = ecosystem_config.path_to_l1_foundry(); let forge = Forge::new(&foundry_contracts_path) .script( &ACCEPT_GOVERNANCE_SCRIPT_PARAMS.script(), diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/setup_legacy_bridge.rs b/zkstack_cli/crates/zkstack/src/commands/chain/setup_legacy_bridge.rs index a05ef04eee3e..8973fccced86 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/setup_legacy_bridge.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/setup_legacy_bridge.rs @@ -42,7 +42,7 @@ pub async fn setup_legacy_bridge( create2factory_salt: contracts_config.create2_factory_salt, create2factory_addr: contracts_config.create2_factory_addr, }; - let foundry_contracts_path = chain_config.path_to_foundry(); + let foundry_contracts_path = chain_config.path_to_l1_foundry(); input.save(shell, SETUP_LEGACY_BRIDGE.input(&chain_config.link_to_code))?; let secrets = chain_config.get_secrets_config()?; diff --git a/zkstack_cli/crates/zkstack/src/commands/dev/commands/clean/mod.rs b/zkstack_cli/crates/zkstack/src/commands/dev/commands/clean/mod.rs index 0929f5e4623f..06dff541f94e 100644 --- a/zkstack_cli/crates/zkstack/src/commands/dev/commands/clean/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/dev/commands/clean/mod.rs @@ -38,7 +38,7 @@ pub fn containers(shell: &Shell) -> anyhow::Result<()> { } pub fn contracts(shell: &Shell, ecosystem_config: &EcosystemConfig) -> anyhow::Result<()> { - let path_to_foundry = ecosystem_config.path_to_foundry(); + let path_to_foundry = ecosystem_config.path_to_l1_foundry(); let contracts_path = ecosystem_config.link_to_code.join("contracts"); logger::info(MSG_CONTRACTS_CLEANING); shell diff --git a/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/gateway_upgrade.rs b/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/gateway_upgrade.rs new file mode 100644 index 000000000000..21fb714bc491 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/gateway_upgrade.rs @@ -0,0 +1,93 @@ +/// TODO(EVM-927): Note that the contents of this file are not useable without Gateway contracts. +use std::path::PathBuf; + +use clap::{Parser, ValueEnum}; +use common::{forge::ForgeScriptArgs, Prompt}; +use serde::{Deserialize, Serialize}; +use strum::EnumIter; +use types::L1Network; +use url::Url; + +use crate::{ + defaults::LOCAL_RPC_URL, + messages::{MSG_L1_RPC_URL_HELP, MSG_L1_RPC_URL_INVALID_ERR, MSG_L1_RPC_URL_PROMPT}, +}; + +#[derive( + Debug, Serialize, Deserialize, Clone, Copy, ValueEnum, EnumIter, strum::Display, PartialEq, Eq, +)] +pub enum GatewayUpgradeStage { + // Deploy contracts + init everything the governance will need to approve the upgrade + NoGovernancePrepare, + // Governance will execute stage 1 of the upgrade, which appends + // a new protocol version and all chains involved must upgrade + GovernanceStage1, + // Governance will execute stage 2 of the upgrade. It is CRUCIAL + // to have it done only after protocol deadline has passed. + GovernanceStage2, + // Finish finalizing tokens, chains, etc + NoGovernanceStage2, + // Registering and setting up gateway chain + GovernanceStage3, + // Deploy CTM + NoGovernanceStage3, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Parser)] +pub struct GatewayUpgradeArgs { + #[clap(flatten)] + #[serde(flatten)] + pub forge_args: ForgeScriptArgs, + #[clap(long, value_enum)] + ecosystem_upgrade_stage: GatewayUpgradeStage, + /// Path to ecosystem contracts + #[clap(long)] + pub ecosystem_contracts_path: Option, + #[clap(long, help = MSG_L1_RPC_URL_HELP)] + pub l1_rpc_url: Option, +} + +impl GatewayUpgradeArgs { + pub fn fill_values_with_prompt( + self, + l1_network: L1Network, + dev: bool, + ) -> GatewayUpgradeArgsFinal { + let l1_rpc_url = self.l1_rpc_url.unwrap_or_else(|| { + let mut prompt = Prompt::new(MSG_L1_RPC_URL_PROMPT); + if dev { + return LOCAL_RPC_URL.to_string(); + } + if l1_network == L1Network::Localhost { + prompt = prompt.default(LOCAL_RPC_URL); + } + prompt + .validate_with(|val: &String| -> Result<(), String> { + Url::parse(val) + .map(|_| ()) + .map_err(|_| MSG_L1_RPC_URL_INVALID_ERR.to_string()) + }) + .ask() + }); + GatewayUpgradeArgsFinal { + forge_args: self.forge_args, + ecosystem_upgrade_stage: self.ecosystem_upgrade_stage, + ecosystem_contracts_path: self.ecosystem_contracts_path, + l1_rpc_url, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Parser)] +pub struct GatewayUpgradeArgsFinal { + #[clap(flatten)] + #[serde(flatten)] + pub forge_args: ForgeScriptArgs, + #[clap(long, value_enum)] + pub ecosystem_upgrade_stage: GatewayUpgradeStage, + /// Path to ecosystem contracts + #[clap(long)] + pub ecosystem_contracts_path: Option, + #[clap(long, help = MSG_L1_RPC_URL_HELP)] + pub l1_rpc_url: String, +} diff --git a/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/mod.rs b/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/mod.rs index c25eebda3d6d..9ee2deacdb1e 100644 --- a/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/mod.rs @@ -1,4 +1,5 @@ pub mod build_transactions; pub mod change_default; pub mod create; +pub mod gateway_upgrade; pub mod init; diff --git a/zkstack_cli/crates/zkstack/src/commands/ecosystem/common.rs b/zkstack_cli/crates/zkstack/src/commands/ecosystem/common.rs index 074913d79fa2..e5ba18fe4c3e 100644 --- a/zkstack_cli/crates/zkstack/src/commands/ecosystem/common.rs +++ b/zkstack_cli/crates/zkstack/src/commands/ecosystem/common.rs @@ -41,7 +41,7 @@ pub async fn deploy_l1( ); deploy_config.save(shell, deploy_config_path)?; - let mut forge = Forge::new(&config.path_to_foundry()) + let mut forge = Forge::new(&config.path_to_l1_foundry()) .script(&DEPLOY_ECOSYSTEM_SCRIPT_PARAMS.script(), forge_args.clone()) .with_ffi() .with_rpc_url(l1_rpc_url.to_string()); diff --git a/zkstack_cli/crates/zkstack/src/commands/ecosystem/init.rs b/zkstack_cli/crates/zkstack/src/commands/ecosystem/init.rs index 1d110c72fb77..309dda7abe5b 100644 --- a/zkstack_cli/crates/zkstack/src/commands/ecosystem/init.rs +++ b/zkstack_cli/crates/zkstack/src/commands/ecosystem/init.rs @@ -146,7 +146,7 @@ async fn deploy_erc20( ) .save(shell, deploy_config_path)?; - let mut forge = Forge::new(&ecosystem_config.path_to_foundry()) + let mut forge = Forge::new(&ecosystem_config.path_to_l1_foundry()) .script(&DEPLOY_ERC20_SCRIPT_PARAMS.script(), forge_args.clone()) .with_ffi() .with_rpc_url(l1_rpc_url) diff --git a/zkstack_cli/crates/zkstack/src/commands/server.rs b/zkstack_cli/crates/zkstack/src/commands/server.rs index 10f267fb8526..702897edbbc1 100644 --- a/zkstack_cli/crates/zkstack/src/commands/server.rs +++ b/zkstack_cli/crates/zkstack/src/commands/server.rs @@ -69,6 +69,7 @@ fn run_server( GeneralConfig::get_path_with_base_path(&chain_config.configs), SecretsConfig::get_path_with_base_path(&chain_config.configs), ContractsConfig::get_path_with_base_path(&chain_config.configs), + None, vec![], ) .context(MSG_FAILED_TO_RUN_SERVER_ERR) diff --git a/zkstack_cli/crates/zkstack/src/enable_evm_emulator.rs b/zkstack_cli/crates/zkstack/src/enable_evm_emulator.rs index 67ff43b75546..bda1bfb3fc81 100644 --- a/zkstack_cli/crates/zkstack/src/enable_evm_emulator.rs +++ b/zkstack_cli/crates/zkstack/src/enable_evm_emulator.rs @@ -28,7 +28,7 @@ pub async fn enable_evm_emulator( let calldata = enable_evm_emulator_contract .encode("chainAllowEvmEmulation", (admin, target_address)) .unwrap(); - let foundry_contracts_path = ecosystem_config.path_to_foundry(); + let foundry_contracts_path = ecosystem_config.path_to_l1_foundry(); let forge = Forge::new(&foundry_contracts_path) .script(&ENABLE_EVM_EMULATOR_PARAMS.script(), forge_args.clone()) .with_ffi()