From 3faa953294ed5eb188dafe9566e3f66fac299a0d Mon Sep 17 00:00:00 2001 From: "ricky.luo" Date: Wed, 11 Mar 2026 15:58:54 +0800 Subject: [PATCH 1/7] change external sign method --- gas-oracle/app/Cargo.lock | 392 +++++++++++++++++++--- gas-oracle/app/Cargo.toml | 6 +- gas-oracle/app/rust-toolchain | 1 - gas-oracle/app/src/da_scalar/l1_scalar.rs | 40 +-- gas-oracle/app/src/gas_price_oracle.rs | 8 +- gas-oracle/app/src/l1_base_fee.rs | 54 ++- gas-oracle/app/src/lib.rs | 1 - gas-oracle/app/src/signer.rs | 39 ++- 8 files changed, 414 insertions(+), 127 deletions(-) delete mode 100644 gas-oracle/app/rust-toolchain diff --git a/gas-oracle/app/Cargo.lock b/gas-oracle/app/Cargo.lock index 73b875129..2f6cccb68 100644 --- a/gas-oracle/app/Cargo.lock +++ b/gas-oracle/app/Cargo.lock @@ -137,7 +137,6 @@ name = "app" version = "0.1.0" dependencies = [ "axum", - "base64 0.22.1", "dotenv", "env_logger", "ethers", @@ -145,18 +144,15 @@ dependencies = [ "flexi_logger", "lazy_static", "log", - "pem", "prometheus", - "reqwest", - "rsa", + "remote-signer-client", + "reqwest 0.11.27", "serde", "serde_json", - "sha2", "thiserror", "tokio", "tower", "tower-http 0.4.4", - "uuid 1.8.0", "zstd 0.13.0", ] @@ -241,9 +237,9 @@ dependencies = [ "bitflags 1.3.2", "bytes", "futures-util", - "http", - "http-body", - "hyper", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", "matchit", "memchr", "mime", @@ -252,7 +248,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "tokio", "tower", "tower-http 0.2.5", @@ -269,8 +265,8 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "mime", ] @@ -1058,7 +1054,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "reqwest", + "reqwest 0.11.27", "serde", "serde_json", "syn 2.0.66", @@ -1120,7 +1116,7 @@ checksum = "e79e5973c26d4baf0ce55520bd732314328cabe53193286671b47144145b9649" dependencies = [ "chrono", "ethers-core", - "reqwest", + "reqwest 0.11.27", "semver", "serde", "serde_json", @@ -1145,7 +1141,7 @@ dependencies = [ "futures-locks", "futures-util", "instant", - "reqwest", + "reqwest 0.11.27", "serde", "serde_json", "thiserror", @@ -1172,12 +1168,12 @@ dependencies = [ "futures-timer", "futures-util", "hashers", - "http", + "http 0.2.12", "instant", "jsonwebtoken", "once_cell", "pin-project", - "reqwest", + "reqwest 0.11.27", "serde", "serde_json", "thiserror", @@ -1528,7 +1524,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap 2.2.6", "slab", "tokio", @@ -1614,6 +1610,16 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -1621,7 +1627,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.4.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -1660,8 +1689,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -1673,6 +1702,25 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -1680,11 +1728,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", - "hyper", - "rustls", + "http 0.2.12", + "hyper 0.14.28", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.4.0", + "hyper 1.5.2", + "hyper-util", + "rustls 0.23.37", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tower-service", + "webpki-roots 1.0.6", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "hyper 1.5.2", + "pin-project-lite", + "socket2", "tokio", - "tokio-rustls", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -1864,7 +1949,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" dependencies = [ "base64 0.21.7", - "pem", + "pem 1.1.1", "ring 0.16.20", "serde", "serde_json", @@ -2307,6 +2392,16 @@ dependencies = [ "base64 0.13.1", ] +[[package]] +name = "pem" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -2564,6 +2659,54 @@ version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" +[[package]] +name = "quinn" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.37", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +dependencies = [ + "bytes", + "rand", + "ring 0.17.8", + "rustc-hash", + "rustls 0.23.37", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.36" @@ -2687,6 +2830,24 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +[[package]] +name = "remote-signer-client" +version = "0.1.0" +source = "git+https://github.com/morph-l2/remote-signer-client#c1d5df7bd377bcb993c0a82bb9dba879dfdfd431" +dependencies = [ + "base64 0.22.1", + "ethers", + "log", + "pem 3.0.5", + "reqwest 0.12.5", + "rsa", + "serde", + "serde_json", + "sha2", + "tokio", + "uuid 1.8.0", +] + [[package]] name = "reqwest" version = "0.11.27" @@ -2699,10 +2860,10 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", - "hyper-rustls", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", + "hyper-rustls 0.24.2", "ipnet", "js-sys", "log", @@ -2710,22 +2871,64 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg 0.50.0", +] + +[[package]] +name = "reqwest" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.2", + "hyper-rustls 0.27.7", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.37", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tokio-rustls 0.26.4", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", - "winreg", + "webpki-roots 0.26.11", + "winreg 0.52.0", ] [[package]] @@ -2832,6 +3035,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -2868,10 +3077,24 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "once_cell", + "ring 0.17.8", + "rustls-pki-types", + "rustls-webpki 0.103.9", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -2881,6 +3104,24 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -2891,6 +3132,17 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" version = "1.0.17" @@ -3247,7 +3499,7 @@ dependencies = [ "fs2", "hex", "once_cell", - "reqwest", + "reqwest 0.11.27", "semver", "serde", "serde_json", @@ -3285,6 +3537,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + [[package]] name = "system-configuration" version = "0.5.1" @@ -3446,7 +3704,17 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls 0.23.37", "tokio", ] @@ -3458,11 +3726,11 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls", + "rustls 0.21.12", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tungstenite", - "webpki-roots", + "webpki-roots 0.25.4", ] [[package]] @@ -3554,8 +3822,8 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "http-range-header", "pin-project-lite", "tower", @@ -3575,8 +3843,8 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "http-range-header", "httpdate", "iri-string", @@ -3662,11 +3930,11 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.12", "httparse", "log", "rand", - "rustls", + "rustls 0.21.12", "sha1", "thiserror", "url", @@ -3900,6 +4168,24 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.6", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "winapi" version = "0.3.9" @@ -4107,6 +4393,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if 1.0.0", + "windows-sys 0.48.0", +] + [[package]] name = "ws_stream_wasm" version = "0.7.4" diff --git a/gas-oracle/app/Cargo.toml b/gas-oracle/app/Cargo.toml index 861ed0e0d..7fbb3b4e1 100644 --- a/gas-oracle/app/Cargo.toml +++ b/gas-oracle/app/Cargo.toml @@ -23,8 +23,4 @@ reqwest = { version = "0.11", default-features = false, features = ["blocking", thiserror = "1.0" eyre = "0.6" zstd = { git = "https://github.com/scroll-tech/zstd-rs", branch = "hack/mul-block", features = ["experimental"]} -rsa = { version = "0.9.6", features = ["sha2"] } -sha2 = "0.10.8" -uuid = { version = "1.3", features = ["v4"] } -base64 = "0.22.1" -pem = "1.1.0" +remote-signer-client = { git = "https://github.com/morph-l2/remote-signer-client", package = "remote-signer-client" } diff --git a/gas-oracle/app/rust-toolchain b/gas-oracle/app/rust-toolchain deleted file mode 100644 index f1d81c421..000000000 --- a/gas-oracle/app/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly-2023-12-03 \ No newline at end of file diff --git a/gas-oracle/app/src/da_scalar/l1_scalar.rs b/gas-oracle/app/src/da_scalar/l1_scalar.rs index 140e8163f..db4581a6c 100644 --- a/gas-oracle/app/src/da_scalar/l1_scalar.rs +++ b/gas-oracle/app/src/da_scalar/l1_scalar.rs @@ -14,10 +14,10 @@ use crate::{ gas_price_oracle_abi::GasPriceOracle, rollup_abi::{CommitBatchCall, Rollup}, }, - external_sign::ExternalSign, metrics::ORACLE_SERVICE_METRICS, signer::send_transaction, }; +use remote_signer_client::SignerClient; use ethers::{abi::AbiDecode, prelude::*, utils::hex}; use serde_json::Value; @@ -30,7 +30,7 @@ pub struct ScalarUpdater { l1_provider: Provider, // L1 provider for HTTP connections l2_provider: Provider, l2_oracle: GasPriceOracle, LocalWallet>>, // L2 gasPrice Oracle - ext_signer: Option, + ext_signer: Option, l1_rollup: Rollup>, // Rollup object for L1 beacon_node: BeaconNode, // Beacon node for blockchain gas_threshold: u64, @@ -47,7 +47,7 @@ impl ScalarUpdater { l1_provider: Provider, l2_provider: Provider, l2_oracle: GasPriceOracle, LocalWallet>>, - ext_signer: Option, + ext_signer: Option, l1_rollup: Rollup>, l1_beacon_rpc: String, gas_threshold: u64, @@ -133,33 +133,23 @@ impl ScalarUpdater { "commit_scalar", ) { // Update commit_scalar - let calldata = self.l2_oracle.set_commit_scalar(U256::from(commit_scalar)).calldata(); - let tx_hash = send_transaction( - self.l2_oracle.address(), - calldata, - &client, - &self.ext_signer, - &self.l2_provider, - ) - .await - .map_err(|e| { - ScalarError::Error(anyhow!(format!("set_commit_scalar error: {:#?}", e))) - })?; + let call = self.l2_oracle.set_commit_scalar(U256::from(commit_scalar)); + let tx_hash = send_transaction(call, &client, &self.ext_signer, &self.l2_provider) + .await + .map_err(|e| { + ScalarError::Error(anyhow!(format!("set_commit_scalar error: {:#?}", e))) + })?; log::info!("set_commit_scalar success, tx_hash: {:#?}", tx_hash); } if self.check_threshold_reached(blob_scalar, current_blob_scalar.as_u64(), "blob_scalar") { // Update blob_scalar - let calldata = self.l2_oracle.set_blob_scalar(U256::from(blob_scalar)).calldata(); - let tx_hash = send_transaction( - self.l2_oracle.address(), - calldata, - &client, - &self.ext_signer, - &self.l2_provider, - ) - .await - .map_err(|e| ScalarError::Error(anyhow!(format!("set_blob_scalar error: {:#?}", e))))?; + let call = self.l2_oracle.set_blob_scalar(U256::from(blob_scalar)); + let tx_hash = send_transaction(call, &client, &self.ext_signer, &self.l2_provider) + .await + .map_err(|e| { + ScalarError::Error(anyhow!(format!("set_blob_scalar error: {:#?}", e))) + })?; log::info!("set_blob_scalar success, tx_hash: {:#?}", tx_hash); } diff --git a/gas-oracle/app/src/gas_price_oracle.rs b/gas-oracle/app/src/gas_price_oracle.rs index fb2d8f29d..817be92af 100644 --- a/gas-oracle/app/src/gas_price_oracle.rs +++ b/gas-oracle/app/src/gas_price_oracle.rs @@ -1,10 +1,10 @@ use crate::{ abi::{gas_price_oracle_abi::GasPriceOracle, rollup_abi::Rollup}, da_scalar::l1_scalar::ScalarUpdater, - external_sign::ExternalSign, l1_base_fee::BaseFeeUpdater, read_parse_env, }; +use remote_signer_client::SignerClient; use ethers::{ prelude::*, providers::{Http, Provider}, @@ -182,20 +182,20 @@ async fn prepare_updater( let use_ext_sign: bool = read_env_var("GAS_ORACLE_EXTERNAL_SIGN", false); let ext_signer = if use_ext_sign { - log::info!("Gas Oracle will use external signer"); + log::info!("Gas Oracle will use remote signer"); let gas_oracle_appid: String = read_parse_env("GAS_ORACLE_EXTERNAL_SIGN_APPID"); let privkey_pem: String = read_parse_env("GAS_ORACLE_EXTERNAL_SIGN_RSA_PRIV"); let sign_address: String = read_parse_env("GAS_ORACLE_EXTERNAL_SIGN_ADDRESS"); let sign_chain: String = read_parse_env("GAS_ORACLE_EXTERNAL_SIGN_CHAIN"); let sign_url: String = read_parse_env("GAS_ORACLE_EXTERNAL_SIGN_URL"); - let signer: ExternalSign = ExternalSign::new( + let signer = SignerClient::new( &gas_oracle_appid, &privkey_pem, &sign_address, &sign_chain, &sign_url, ) - .map_err(|e| anyhow!(format!("Prepare ExternalSign err: {:?}", e))) + .map_err(|e| anyhow!(format!("Prepare SignerClient err: {:?}", e))) .unwrap(); Some(signer) } else { diff --git a/gas-oracle/app/src/l1_base_fee.rs b/gas-oracle/app/src/l1_base_fee.rs index aaa977b07..833e018a6 100644 --- a/gas-oracle/app/src/l1_base_fee.rs +++ b/gas-oracle/app/src/l1_base_fee.rs @@ -1,11 +1,12 @@ use std::{str::FromStr, sync::Arc}; use crate::{ - abi::gas_price_oracle_abi::GasPriceOracle, external_sign::ExternalSign, - metrics::ORACLE_SERVICE_METRICS, signer::send_transaction, OracleError, + abi::gas_price_oracle_abi::GasPriceOracle, metrics::ORACLE_SERVICE_METRICS, + signer::send_transaction, OracleError, }; use ethers::prelude::*; use eyre::anyhow; +use remote_signer_client::SignerClient; const MAX_BASE_FEE: u128 = 1000 * 10i32.pow(9) as u128; // 1000Gwei const MAX_BLOB_BASE_FEE: u128 = 100 * 10i32.pow(9) as u128; // 100Gwei @@ -13,7 +14,7 @@ const MAX_BLOB_BASE_FEE: u128 = 100 * 10i32.pow(9) as u128; // 100Gwei pub struct BaseFeeUpdater { l1_provider: Provider, l2_provider: Provider, - ext_signer: Option, + ext_signer: Option, l2_oracle: GasPriceOracle, LocalWallet>>, gas_threshold: u64, l1_base_fee_buffer: u64, @@ -24,7 +25,7 @@ impl BaseFeeUpdater { pub fn new( l1_provider: Provider, l2_provider: Provider, - ext_signer: Option, + ext_signer: Option, l2_oracle: GasPriceOracle, LocalWallet>>, gas_threshold: u64, l1_base_fee_buffer: u64, @@ -144,24 +145,17 @@ impl BaseFeeUpdater { let client: Arc, LocalWallet>> = self.l2_oracle.client(); if need_update { // Update calldata basefee and blob baseFee - let calldata = self + let call = self .l2_oracle - .set_l1_base_fee_and_blob_base_fee(l1_base_fee, l1_blob_base_fee) - .calldata(); - let tx_hash = send_transaction( - self.l2_oracle.address(), - calldata, - &client, - &self.ext_signer, - &self.l2_provider, - ) - .await - .map_err(|e| { - OracleError::L1BaseFeeError(anyhow!(format!( - "set_l1_base_fee_and_blob_base_fee error: {:#?}", - e - ))) - })?; + .set_l1_base_fee_and_blob_base_fee(l1_base_fee, l1_blob_base_fee); + let tx_hash = send_transaction(call, &client, &self.ext_signer, &self.l2_provider) + .await + .map_err(|e| { + OracleError::L1BaseFeeError(anyhow!(format!( + "set_l1_base_fee_and_blob_base_fee error: {:#?}", + e + ))) + })?; log::info!("set_l1_base_fee_and_blob_base_fee success, tx_hash: {:#?}", tx_hash); return Ok(()); @@ -180,18 +174,12 @@ impl BaseFeeUpdater { ); if need_update { // Set l1_base_fee for l2. - let calldata = self.l2_oracle.set_l1_base_fee(l1_base_fee).calldata(); - let tx_hash = send_transaction( - self.l2_oracle.address(), - calldata, - &client, - &self.ext_signer, - &self.l2_provider, - ) - .await - .map_err(|e| { - OracleError::L1BaseFeeError(anyhow!(format!("set_l1_base_fee error: {:#?}", e))) - })?; + let call = self.l2_oracle.set_l1_base_fee(l1_base_fee); + let tx_hash = send_transaction(call, &client, &self.ext_signer, &self.l2_provider) + .await + .map_err(|e| { + OracleError::L1BaseFeeError(anyhow!(format!("set_l1_base_fee error: {:#?}", e))) + })?; log::info!("set_l1_base_fee success, tx_hash: {:#?}", tx_hash); } diff --git a/gas-oracle/app/src/lib.rs b/gas-oracle/app/src/lib.rs index d5055f4ae..60e6fa0de 100644 --- a/gas-oracle/app/src/lib.rs +++ b/gas-oracle/app/src/lib.rs @@ -7,7 +7,6 @@ mod l1_base_fee; mod metrics; mod da_scalar; -mod external_sign; mod signer; use abi::gas_price_oracle_abi::GasPriceOracleErrors; pub use error::*; diff --git a/gas-oracle/app/src/signer.rs b/gas-oracle/app/src/signer.rs index 929939b12..8fba7208f 100644 --- a/gas-oracle/app/src/signer.rs +++ b/gas-oracle/app/src/signer.rs @@ -1,4 +1,6 @@ use ethers::{ + abi::FunctionExt, + contract::builders::ContractCall, middleware::SignerMiddleware, prelude::*, providers::{Http, Provider}, @@ -6,17 +8,33 @@ use ethers::{ types::transaction::eip2718::TypedTransaction, }; use eyre::anyhow; +use remote_signer_client::SignerClient; use std::{error::Error, str::FromStr, sync::Arc}; -use crate::{contract_error, external_sign::ExternalSign, read_env_var}; +use crate::{contract_error, read_env_var}; -pub async fn send_transaction( - contract: Address, - calldata: Option, +/// Send a contract call as a transaction. +/// +/// `call` carries both the ABI method info (for extracting the method signature) +/// and the encoded calldata. The method signature is forwarded to the remote +/// signer so it can apply policy checks. +pub async fn send_transaction( + call: ContractCall, local_signer: &Arc, LocalWallet>>, - ext_signer: &Option, + ext_signer: &Option, l2_provider: &Provider, -) -> Result> { +) -> Result> +where + M: ethers::providers::Middleware, + D: ethers::abi::Detokenize, +{ + let contract = match call.tx.to() { + Some(NameOrAddress::Address(addr)) => *addr, + _ => Address::zero(), + }; + let method_sig = call.function.abi_signature(); + let calldata = call.calldata(); + // Estimate eip1559_fees let gas_data = local_signer .estimate_eip1559_fees(Some(eip1559_estimator)) @@ -45,7 +63,7 @@ pub async fn send_transaction( })?; // Sign and send - let signed_tx = sign_tx(&mut tx, local_signer, ext_signer) + let signed_tx = sign_tx(&mut tx, local_signer, ext_signer, &method_sig) .await .map_err(|e| anyhow!("sign_tx error: {}", e))?; @@ -71,11 +89,12 @@ pub async fn send_transaction( async fn sign_tx( tx: &mut TypedTransaction, local_signer: &Arc, LocalWallet>>, - ext_signer: &Option, + ext_signer: &Option, + method_sig: &str, ) -> Result> { if let Some(signer) = ext_signer { - log::info!("request ext sign"); - Ok(signer.request_sign(tx).await?) + log::info!("request remote sign, method_sig: {}", method_sig); + Ok(signer.sign(tx, method_sig).await?) } else { log::info!("request local sign"); let signature = local_signer.signer().sign_transaction(tx).await?; From da46d9fea42b74b1f3b4dc6796932835ab322a67 Mon Sep 17 00:00:00 2001 From: "ricky.luo" Date: Wed, 11 Mar 2026 16:05:46 +0800 Subject: [PATCH 2/7] revoke rust toolchain file --- gas-oracle/app/rust-toolchain | 1 + 1 file changed, 1 insertion(+) create mode 100644 gas-oracle/app/rust-toolchain diff --git a/gas-oracle/app/rust-toolchain b/gas-oracle/app/rust-toolchain new file mode 100644 index 000000000..f1d81c421 --- /dev/null +++ b/gas-oracle/app/rust-toolchain @@ -0,0 +1 @@ +nightly-2023-12-03 \ No newline at end of file From f7177b3e8d6d5f66c7174cba32aa45f14233a717 Mon Sep 17 00:00:00 2001 From: "ricky.luo" Date: Wed, 11 Mar 2026 16:16:08 +0800 Subject: [PATCH 3/7] remove unused file --- gas-oracle/app/src/external_sign.rs | 224 ---------------------------- 1 file changed, 224 deletions(-) delete mode 100644 gas-oracle/app/src/external_sign.rs diff --git a/gas-oracle/app/src/external_sign.rs b/gas-oracle/app/src/external_sign.rs deleted file mode 100644 index 0a30a926c..000000000 --- a/gas-oracle/app/src/external_sign.rs +++ /dev/null @@ -1,224 +0,0 @@ -use base64::{engine::general_purpose, Engine}; -use ethers::{abi::AbiEncode, types::*, utils::hex}; -use pem::{encode_config, EncodeConfig, Pem}; -use reqwest::Client; -use rsa::{ - pkcs8::{DecodePrivateKey, EncodePublicKey}, - Pkcs1v15Sign, RsaPrivateKey, -}; -use serde::{Deserialize, Serialize}; -use sha2::{Digest, Sha256}; -use std::{error::Error, time::UNIX_EPOCH}; -use transaction::eip2718::TypedTransaction; -use uuid::Uuid; - -#[derive(Clone)] -pub struct ExternalSign { - appid: String, - pub address: String, - privkey: RsaPrivateKey, - chain: String, - client: Client, - url: String, -} - -#[derive(Serialize, Debug)] -struct BusinessData { - appid: String, - data: String, - noncestr: String, - timestamp: String, -} - -#[derive(Serialize, Debug)] -struct ReqData { - #[serde(flatten)] - business_data: BusinessData, - #[serde(rename = "bizSignature")] - biz_signature: String, - #[serde(rename = "publicKey")] - public_key: String, - #[serde(rename = "txData")] - tx_data: String, // hex string of tx -} - -#[derive(Serialize, Debug)] -struct Data { - address: String, - chain: String, - sha3: String, -} - -#[derive(Deserialize)] -struct Response { - result: ResultData, -} - -#[derive(Deserialize)] -struct ResultData { - #[serde(rename = "signDatas")] - sign_datas: Vec, -} - -#[derive(Deserialize)] -struct SignData { - sign: String, -} - -impl ExternalSign { - pub fn new( - appid: &str, - privkey_pem: &str, - address: &str, - chain: &str, - url: &str, - ) -> Result> { - let privkey = RsaPrivateKey::from_pkcs8_pem(&reformat_pem(privkey_pem))?; - let client = Client::new(); - Ok(ExternalSign { - appid: appid.to_string(), - address: address.to_string(), - privkey, - chain: chain.to_string(), - client, - url: url.to_string(), - }) - } - - pub async fn request_sign(&self, tx: &TypedTransaction) -> Result> { - let data = self.new_data(&hex::encode_prefixed(tx.sighash().encode()))?; - let tx_info = - hex::encode(tx.rlp_signed(&Signature::try_from(vec![0u8; 65].as_slice()).unwrap())); - - let req_data = self.craft_req_data(data, tx_info)?; - - let rt = self.do_request(&self.url, &req_data).await?; - log::debug!("ext_sign response: {:?}", rt); - - let response: Response = serde_json::from_str(&rt)?; - if response.result.sign_datas.is_empty() { - return Err("ext_sign response sign_datas empty".into()); - } - if response.result.sign_datas[0].sign.len() < 132 { - //hex prefix + 65bytes sig - return Err("ext_sign response sign data invalid".into()); - } - - let sig = hex::decode(&response.result.sign_datas[0].sign[2..])?; - let signed_tx: Bytes = tx.rlp_signed(&Signature::try_from(sig.as_slice())?); - Ok(signed_tx) - } - - fn new_data(&self, hash: &str) -> Result> { - Ok(Data { - address: self.address.clone(), - chain: self.chain.clone(), - sha3: hash.to_string(), - }) - } - - fn craft_req_data(&self, data: Data, tx_info: String) -> Result> { - let nonce_str = Uuid::new_v4().to_string(); - let data_bs = serde_json::to_string(&data)?; - - let business_data = BusinessData { - appid: self.appid.clone(), - data: data_bs, - noncestr: nonce_str, - timestamp: UNIX_EPOCH.elapsed()?.as_secs().to_string(), - }; - - let business_data_bs = serde_json::to_string(&business_data)?; - let hashed = sha2::Sha256::digest(business_data_bs.as_bytes()); - let signature = self.privkey.sign(Pkcs1v15Sign::new::(), &hashed)?; - let hex_sig = hex::encode(signature); - - let pubkey = self.privkey.to_public_key().to_public_key_der()?; - let pubkey_base64 = base64::engine::general_purpose::STANDARD.encode(pubkey.as_ref()); - Ok(ReqData { - business_data, - biz_signature: hex_sig, - public_key: pubkey_base64, - tx_data: tx_info, - }) - } - - async fn do_request(&self, url: &str, payload: &ReqData) -> Result> { - log::debug!("===payload: {:?}", serde_json::to_string(payload).unwrap()); - let response: reqwest::Response = self.client.post(url).json(&payload).send().await?; - if !response.status().is_success() { - return Err(format!("ext_sign response status not ok: {:?}", response.status()).into()); - } - Ok(response.text().await?) - } -} - -fn reformat_pem(pem_string: &str) -> String { - // Decode the base64 encoded string - let key_bytes = general_purpose::STANDARD.decode(pem_string).expect("Failed to decode base64"); - - // Create a PEM object with the required format - let pem = Pem { tag: String::from("PRIVATE KEY"), contents: key_bytes }; - - // Encode the PEM object to a string with standard line width of 64 characters - let config = EncodeConfig { line_ending: pem::LineEnding::LF }; - encode_config(&pem, config) -} - -#[tokio::test] -#[ignore] -async fn test_sign() -> Result<(), Box> { - use crate::read_parse_env; - use ethers::{ - middleware::SignerMiddleware, - providers::{Http, Middleware, Provider}, - signers::{Signer, Wallet}, - }; - use std::{str::FromStr, sync::Arc}; - - // let path = "./../ext_signer_private.key"; - // let file = File::open(path)?; - // let reader = BufReader::new(file); - - // let mut privkey_base64 = String::new(); - // for line in reader.lines() { - // let line_str = line?; - // privkey_base64.push_str(&line_str); - // privkey_base64.push('\n'); - // } - dotenv::dotenv().ok(); - env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init(); - let privkey_pem: String = read_parse_env("GAS_ORACLE_EXTERNAL_SIGN_RSA_PRIV"); - // appid := "morph-tx-submitter-399A1722-3F2C-4E39-ABD2-1B65D02C66BA" - // rsaPrivStr := "" - // url := "http://localhost:8080/v1/sign/tx_sign" - // addr := "0x33d5b507868b7e8ac930cd3bde9eadd60c638479" - // chain := "QANET-L1" - // chainid := big.NewInt(900) - // signer := types.LatestSignerForChainID(chainid) - let ext_signer: ExternalSign = ExternalSign::new( - "gas-oracle-165B3138-0C01-430C-9845-37459D5BEB46", - &privkey_pem, - "0x4faad0ea547e75b0e4a026d766aaef4339762ac3", - "QANET-L2", - "http://localhost:8080/v1/sign/tx_sign", - )?; - - let l2_provider = Provider::::try_from("http://localhost:8545")?; - let l2_signer = Arc::new(SignerMiddleware::new( - l2_provider.clone(), - Wallet::from_str("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")? - .with_chain_id(l2_provider.get_chainid().await?.as_u64()), - )); - let req = Eip1559TransactionRequest::new() - .to(Address::from_str("0x099f9e4ecc7fb2b4fd759ce0c2c2c3072b77e9bc")?) - .from(Address::from_str("0x4faad0ea547e75b0e4a026d766aaef4339762ac3")?); - let mut tx = TypedTransaction::Eip1559(req); - l2_signer.fill_transaction(&mut tx, None).await?; - - log::info!("====request_sign"); - let raw_tx = ext_signer.request_sign(&tx).await?; - let pending_tx = l2_provider.send_raw_transaction(raw_tx).await?; - pending_tx.await.expect("send_raw_transaction"); - Ok(()) -} From 470b2de38b42658e12a3554678355331e4a2e6eb Mon Sep 17 00:00:00 2001 From: "ricky.luo" Date: Wed, 11 Mar 2026 16:24:59 +0800 Subject: [PATCH 4/7] fix review problems --- gas-oracle/app/src/gas_price_oracle.rs | 3 +-- gas-oracle/app/src/signer.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/gas-oracle/app/src/gas_price_oracle.rs b/gas-oracle/app/src/gas_price_oracle.rs index 817be92af..74655abb3 100644 --- a/gas-oracle/app/src/gas_price_oracle.rs +++ b/gas-oracle/app/src/gas_price_oracle.rs @@ -195,8 +195,7 @@ async fn prepare_updater( &sign_chain, &sign_url, ) - .map_err(|e| anyhow!(format!("Prepare SignerClient err: {:?}", e))) - .unwrap(); + .map_err(|e| anyhow!("Prepare SignerClient err: {:?}", e))?; Some(signer) } else { log::info!("Gas Oracle will use local signer"); diff --git a/gas-oracle/app/src/signer.rs b/gas-oracle/app/src/signer.rs index 8fba7208f..8319b3139 100644 --- a/gas-oracle/app/src/signer.rs +++ b/gas-oracle/app/src/signer.rs @@ -30,7 +30,7 @@ where { let contract = match call.tx.to() { Some(NameOrAddress::Address(addr)) => *addr, - _ => Address::zero(), + _ => return Err(anyhow!("send_transaction: contract address not set in call").into()), }; let method_sig = call.function.abi_signature(); let calldata = call.calldata(); From 4db18e6f1bc7012e7f6e33d88201ec43a9e06b16 Mon Sep 17 00:00:00 2001 From: "ricky.luo" Date: Wed, 11 Mar 2026 16:27:47 +0800 Subject: [PATCH 5/7] replace test's signer --- gas-oracle/app/src/da_scalar/l1_scalar.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gas-oracle/app/src/da_scalar/l1_scalar.rs b/gas-oracle/app/src/da_scalar/l1_scalar.rs index db4581a6c..1f653915b 100644 --- a/gas-oracle/app/src/da_scalar/l1_scalar.rs +++ b/gas-oracle/app/src/da_scalar/l1_scalar.rs @@ -464,8 +464,7 @@ mod tests { let l2_oracle_contract = GasPriceOracle::new(l2_oracle_address, l2_signer); - let ext_signer: ExternalSign = - ExternalSign::new("appid", "privkey_pem", "address", "chain", "url").unwrap(); + let ext_signer = SignerClient::new("appid", "privkey_pem", "address", "chain", "url").unwrap(); let mut overhead: ScalarUpdater = ScalarUpdater::new( l1_provider, l2_provider, From badbbc316627d24711ecd8962875f74d2f8ad923 Mon Sep 17 00:00:00 2001 From: "ricky.luo" Date: Thu, 12 Mar 2026 16:32:02 +0800 Subject: [PATCH 6/7] change token price oracle sign pkg to new one --- token-price-oracle/client/l2_client.go | 13 ++-- token-price-oracle/client/sign.go | 76 +++++++---------------- token-price-oracle/go.mod | 17 ++--- token-price-oracle/go.sum | 51 +++++---------- token-price-oracle/updater/token_price.go | 6 +- token-price-oracle/updater/tx_manager.go | 24 +++++-- 6 files changed, 79 insertions(+), 108 deletions(-) diff --git a/token-price-oracle/client/l2_client.go b/token-price-oracle/client/l2_client.go index 1568b068c..bb0c25d14 100644 --- a/token-price-oracle/client/l2_client.go +++ b/token-price-oracle/client/l2_client.go @@ -5,14 +5,15 @@ import ( "fmt" "math/big" - "github.com/morph-l2/externalsign" + "morph-l2/token-price-oracle/config" + "github.com/morph-l2/go-ethereum/accounts/abi/bind" "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/core/types" "github.com/morph-l2/go-ethereum/crypto" "github.com/morph-l2/go-ethereum/ethclient" "github.com/morph-l2/go-ethereum/log" - "morph-l2/token-price-oracle/config" + "github.com/morph-l2/remote-signer-client/go/signer" ) // L2Client wraps L2 chain client @@ -64,13 +65,12 @@ func NewL2Client(rpcURL string, cfg *config.Config) (*L2Client, error) { if cfg.ExternalSign { // External sign mode - rsaPriv, err := externalsign.ParseRsaPrivateKey(cfg.ExternalSignRsaPriv) + rsaPriv, err := signer.ParseRsaPrivateKey(cfg.ExternalSignRsaPriv) if err != nil { return nil, fmt.Errorf("failed to parse RSA private key: %w", err) } - l2Client.signer = NewSigner( - true, + l2Client.signer, err = NewSigner( cfg.ExternalSignAppid, rsaPriv, cfg.ExternalSignAddress, @@ -78,6 +78,9 @@ func NewL2Client(rpcURL string, cfg *config.Config) (*L2Client, error) { cfg.ExternalSignUrl, chainID, ) + if err != nil { + return nil, fmt.Errorf("failed to create signer: %w", err) + } fromAddr := common.HexToAddress(cfg.ExternalSignAddress) ethSigner := types.NewLondonSigner(chainID) diff --git a/token-price-oracle/client/sign.go b/token-price-oracle/client/sign.go index 392879a4f..4a89f5f79 100644 --- a/token-price-oracle/client/sign.go +++ b/token-price-oracle/client/sign.go @@ -6,75 +6,43 @@ import ( "fmt" "math/big" - "github.com/morph-l2/externalsign" "github.com/morph-l2/go-ethereum" "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/core/types" "github.com/morph-l2/go-ethereum/log" + remotesigner "github.com/morph-l2/remote-signer-client/go/signer" ) // Signer handles transaction signing with support for both local and external signing type Signer struct { - externalSign bool - externalSigner *externalsign.ExternalSign - externalSignUrl string + remoteClient *remotesigner.Client externalSignAddress common.Address chainID *big.Int - signer types.Signer } // NewSigner creates a new Signer instance func NewSigner( - externalSign bool, - externalSignAppid string, - externalRsaPriv *rsa.PrivateKey, - externalSignAddress string, - externalSignChain string, - externalSignUrl string, + appid string, + rsaPriv *rsa.PrivateKey, + address string, + chain string, + url string, chainID *big.Int, -) *Signer { - signer := types.NewLondonSigner(chainID) - - s := &Signer{ - externalSign: externalSign, - externalSignUrl: externalSignUrl, - externalSignAddress: common.HexToAddress(externalSignAddress), - chainID: chainID, - signer: signer, - } - - if externalSign { - s.externalSigner = externalsign.NewExternalSign( - externalSignAppid, - externalRsaPriv, - externalSignAddress, - externalSignChain, - signer, - ) - log.Info("External signer initialized", - "address", externalSignAddress, - "chain", externalSignChain) - } - - return s -} - -// Sign signs a transaction using either external or local signing -func (s *Signer) Sign(tx *types.Transaction) (*types.Transaction, error) { - if !s.externalSign { - return nil, fmt.Errorf("local signing not supported in Signer, use bind.TransactOpts") - } - - signedTx, err := s.externalSigner.RequestSign(s.externalSignUrl, tx) +) (*Signer, error) { + remoteClient, err := remotesigner.NewClient(appid, rsaPriv, address, chain, url, types.NewLondonSigner(chainID)) if err != nil { - return nil, fmt.Errorf("external sign request failed: %w", err) + return nil, fmt.Errorf("failed to create remote signer client: %w", err) } - return signedTx, nil -} -// IsExternalSign returns whether external signing is enabled -func (s *Signer) IsExternalSign() bool { - return s.externalSign + log.Info("External signer initialized", + "address", address, + "chain", chain) + + return &Signer{ + remoteClient: remoteClient, + externalSignAddress: common.HexToAddress(address), + chainID: chainID, + }, nil } // GetFromAddress returns the signer's address @@ -88,6 +56,7 @@ func (s *Signer) CreateAndSignTx( client *L2Client, to common.Address, callData []byte, + methodSig string, ) (*types.Transaction, error) { from := s.externalSignAddress @@ -134,8 +103,9 @@ func (s *Signer) CreateAndSignTx( "nonce", nonce, "gas", gas, "gasFeeCap", caps.FeeCap, - "gasTipCap", caps.TipCap) + "gasTipCap", caps.TipCap, + "methodSig", methodSig) // Sign transaction - return s.Sign(tx) + return s.remoteClient.Sign(tx, methodSig) } diff --git a/token-price-oracle/go.mod b/token-price-oracle/go.mod index 02292b9e8..ed442afee 100644 --- a/token-price-oracle/go.mod +++ b/token-price-oracle/go.mod @@ -8,8 +8,8 @@ replace ( ) require ( - github.com/morph-l2/externalsign v0.3.1 github.com/morph-l2/go-ethereum v1.10.14-0.20260211074551-4f0f6e6bd141 + github.com/morph-l2/remote-signer-client/go v0.0.0-20260312080033-d078d86ddbe9 github.com/prometheus/client_golang v1.17.0 github.com/sirupsen/logrus v1.9.3 github.com/urfave/cli v1.22.17 @@ -36,7 +36,7 @@ require ( github.com/go-kit/kit v0.12.0 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-resty/resty/v2 v2.13.1 // indirect + github.com/go-resty/resty/v2 v2.17.2 // indirect github.com/go-stack/stack v1.8.1 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect @@ -59,6 +59,7 @@ require ( github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect @@ -76,12 +77,12 @@ require ( github.com/tklauser/numcpus v0.7.0 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect - golang.org/x/crypto v0.35.0 // indirect - golang.org/x/net v0.25.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - golang.org/x/time v0.5.0 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect + golang.org/x/time v0.12.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/urfave/cli.v1 v1.20.0 // indirect diff --git a/token-price-oracle/go.sum b/token-price-oracle/go.sum index a0b161877..a4ae25247 100644 --- a/token-price-oracle/go.sum +++ b/token-price-oracle/go.sum @@ -67,8 +67,8 @@ github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/go-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g= -github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0= +github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk= +github.com/go-resty/resty/v2 v2.17.2/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= @@ -145,10 +145,10 @@ github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqky github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/morph-l2/externalsign v0.3.1 h1:UYFDZFB0L85A4rDvuwLNBiGEi0kSmg9AZ2v8Q5O4dQo= -github.com/morph-l2/externalsign v0.3.1/go.mod h1:b6NJ4GUiiG/gcSJsp3p8ExsIs4ZdphlrVALASnVoGJE= github.com/morph-l2/go-ethereum v1.10.14-0.20260211074551-4f0f6e6bd141 h1:A8eygErKU6WKMipGWIemzwLeYkIGLd9yb/Ry3x+J9PQ= github.com/morph-l2/go-ethereum v1.10.14-0.20260211074551-4f0f6e6bd141/go.mod h1:nkVzHjQWCOjvukQW8ittlwX+Xz9gmVHrP7mUi7zoHTs= +github.com/morph-l2/remote-signer-client/go v0.0.0-20260312080033-d078d86ddbe9 h1:d2nKLUgiEJsQmpSWEiGbsC+sZXQCM4y/3EzyXkoMM60= +github.com/morph-l2/remote-signer-client/go v0.0.0-20260312080033-d078d86ddbe9/go.mod h1:slD6GmYEwLHn4Yj/kO8/1QF3iaYlVVAXg2ZnGr8SW/8= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -237,72 +237,49 @@ github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3C github.com/urfave/cli v1.22.17 h1:SYzXoiPfQjHBbkYxbew5prZHS1TOLT3ierW8SYLqtVQ= github.com/urfave/cli v1.22.17/go.mod h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/token-price-oracle/updater/token_price.go b/token-price-oracle/updater/token_price.go index 42503fe09..ea7f473a7 100644 --- a/token-price-oracle/updater/token_price.go +++ b/token-price-oracle/updater/token_price.go @@ -202,9 +202,13 @@ func (u *PriceUpdater) update(ctx context.Context) error { "total_tokens", len(tokenIDs)) // Step 3: Update prices on L2 + methodSig, err := abiMethodSig(bindings.L2TokenRegistryMetaData, "batchUpdatePrices") + if err != nil { + return fmt.Errorf("failed to resolve method sig: %w", err) + } receipt, err := u.txManager.SendTransaction(ctx, func(auth *bind.TransactOpts) (*types.Transaction, error) { return u.registryContract.BatchUpdatePrices(auth, tokenIDsToUpdate, pricesToUpdate) - }) + }, methodSig) if err != nil { log.Error("Failed to send transaction", "error", err) diff --git a/token-price-oracle/updater/tx_manager.go b/token-price-oracle/updater/tx_manager.go index 0ae0c8417..ad942c75b 100644 --- a/token-price-oracle/updater/tx_manager.go +++ b/token-price-oracle/updater/tx_manager.go @@ -13,6 +13,20 @@ import ( "morph-l2/token-price-oracle/client" ) +// abiMethodSig returns the canonical method signature string (e.g. "batchUpdatePrices(uint16[],uint256[])") +// for the named method, looked up from the contract's MetaData ABI. +func abiMethodSig(meta *bind.MetaData, method string) (string, error) { + parsed, err := meta.GetAbi() + if err != nil { + return "", fmt.Errorf("failed to parse ABI: %w", err) + } + m, ok := parsed.Methods[method] + if !ok { + return "", fmt.Errorf("method %q not found in ABI", method) + } + return m.Sig, nil +} + // TxManager manages transaction sending to avoid nonce conflicts type TxManager struct { l2Client *client.L2Client @@ -29,12 +43,14 @@ func NewTxManager(l2Client *client.L2Client) *TxManager { // SendTransaction sends a transaction in a thread-safe manner // It ensures only one transaction is sent at a time to avoid nonce conflicts // Before sending, it checks if there are any pending transactions by comparing nonces -func (m *TxManager) SendTransaction(ctx context.Context, txFunc func(*bind.TransactOpts) (*types.Transaction, error)) (*types.Receipt, error) { +// methodSig is the human-readable method signature (e.g. "batchUpdatePrices(uint16[],uint256[])") +// and is only used for external signing (remote signer V2 API). +func (m *TxManager) SendTransaction(ctx context.Context, txFunc func(*bind.TransactOpts) (*types.Transaction, error), methodSig string) (*types.Receipt, error) { m.mu.Lock() defer m.mu.Unlock() if m.l2Client.IsExternalSign() { - return m.sendWithExternalSign(ctx, txFunc) + return m.sendWithExternalSign(ctx, txFunc, methodSig) } return m.sendWithLocalSign(ctx, txFunc) } @@ -115,7 +131,7 @@ func (m *TxManager) sendWithLocalSign(ctx context.Context, txFunc func(*bind.Tra } // sendWithExternalSign sends transaction using external signing service -func (m *TxManager) sendWithExternalSign(ctx context.Context, txFunc func(*bind.TransactOpts) (*types.Transaction, error)) (*types.Receipt, error) { +func (m *TxManager) sendWithExternalSign(ctx context.Context, txFunc func(*bind.TransactOpts) (*types.Transaction, error), methodSig string) (*types.Receipt, error) { signer := m.l2Client.GetSigner() if signer == nil { return nil, fmt.Errorf("external signer is not initialized") @@ -172,7 +188,7 @@ func (m *TxManager) sendWithExternalSign(ctx context.Context, txFunc func(*bind. "calldata_len", len(callData)) // Create and sign transaction using external signer - signedTx, err := signer.CreateAndSignTx(ctx, m.l2Client, toAddr, callData) + signedTx, err := signer.CreateAndSignTx(ctx, m.l2Client, toAddr, callData, methodSig) if err != nil { return nil, fmt.Errorf("failed to create and sign transaction: %w", err) } From 163c64ebb5e874fa6952c82df5378096672f937a Mon Sep 17 00:00:00 2001 From: "ricky.luo" Date: Thu, 12 Mar 2026 17:07:06 +0800 Subject: [PATCH 7/7] remove useless blank line --- token-price-oracle/client/l2_client.go | 1 - 1 file changed, 1 deletion(-) diff --git a/token-price-oracle/client/l2_client.go b/token-price-oracle/client/l2_client.go index bb0c25d14..d9140ec74 100644 --- a/token-price-oracle/client/l2_client.go +++ b/token-price-oracle/client/l2_client.go @@ -6,7 +6,6 @@ import ( "math/big" "morph-l2/token-price-oracle/config" - "github.com/morph-l2/go-ethereum/accounts/abi/bind" "github.com/morph-l2/go-ethereum/common" "github.com/morph-l2/go-ethereum/core/types"