From cd9d182ea234af03917ea1d86217f1049cbbb98d Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Fri, 20 Oct 2023 10:43:17 +0100 Subject: [PATCH 1/4] Fetch Ethereum relayer key from env --- apps/src/lib/cli/utils.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apps/src/lib/cli/utils.rs b/apps/src/lib/cli/utils.rs index 26cc38ff7f..d937a249df 100644 --- a/apps/src/lib/cli/utils.rs +++ b/apps/src/lib/cli/utils.rs @@ -6,6 +6,9 @@ use std::str::FromStr; use clap::{ArgAction, ArgMatches}; use color_eyre::eyre::Result; +use data_encoding::HEXLOWER_PERMISSIVE; +use namada::eth_bridge::ethers::core::k256::elliptic_curve::SecretKey as Secp256k1Sk; +use namada::eth_bridge::ethers::signers::{Signer, Wallet}; use super::args; use super::context::{Context, FromContext}; @@ -362,3 +365,20 @@ pub fn safe_exit(_: i32) -> ! { panic!("Test failed because the client exited unexpectedly.") } + +/// Load an Ethereum wallet from the environment. +/// +/// If no chain id is provided, Ethereum main net is assumed. +#[allow(dead_code)] +pub fn get_eth_signer_from_env(chain_id: Option) -> Option { + const RELAYER_KEY: &str = "NAMADA_RELAYER_KEY"; + + let relayer_key = std::env::var(RELAYER_KEY).ok()?; + let relayer_key = HEXLOWER_PERMISSIVE.decode(relayer_key.as_ref()).ok()?; + let relayer_key = Secp256k1Sk::from_slice(&relayer_key).ok()?; + + let wallet: Wallet<_> = relayer_key.into(); + let wallet = wallet.with_chain_id(chain_id.unwrap_or(1)); + + Some(wallet) +} From 8f841068c15072d1570ad8a9336b25159fc80e66 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Fri, 20 Oct 2023 11:25:00 +0100 Subject: [PATCH 2/4] Require relayer to specify eth key --- apps/src/lib/cli/relayer.rs | 16 +++++----------- apps/src/lib/cli/utils.rs | 31 ++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/apps/src/lib/cli/relayer.rs b/apps/src/lib/cli/relayer.rs index 3322e84e2f..133930e8c0 100644 --- a/apps/src/lib/cli/relayer.rs +++ b/apps/src/lib/cli/relayer.rs @@ -1,7 +1,4 @@ -use std::sync::Arc; - use color_eyre::eyre::{eyre, Report, Result}; -use namada::eth_bridge::ethers::providers::{Http, Provider}; use namada::ledger::eth_bridge::{bridge_pool, validator_set}; use namada::types::control_flow::ProceedOrElse; use namada::types::io::Io; @@ -10,6 +7,7 @@ use crate::cli; use crate::cli::api::{CliApi, CliClient}; use crate::cli::args::{CliToSdk, CliToSdkCtxless}; use crate::cli::cmds::*; +use crate::cli::utils::get_eth_rpc_client; fn error() -> Report { eyre!("Fatal error") @@ -74,10 +72,8 @@ impl CliApi { .wait_until_node_is_synced::() .await .proceed_or_else(error)?; - let eth_client = Arc::new( - Provider::::try_from(&args.eth_rpc_endpoint) - .unwrap(), - ); + let eth_client = + get_eth_rpc_client(&args.eth_rpc_endpoint, None); let args = args.to_sdk_ctxless(); bridge_pool::relay_bridge_pool_proof::<_, _, IO>( eth_client, &client, args, @@ -191,10 +187,8 @@ impl CliApi { .wait_until_node_is_synced::() .await .proceed_or_else(error)?; - let eth_client = Arc::new( - Provider::::try_from(&args.eth_rpc_endpoint) - .unwrap(), - ); + let eth_client = + get_eth_rpc_client(&args.eth_rpc_endpoint, None); let args = args.to_sdk_ctxless(); validator_set::relay_validator_set_update::<_, _, IO>( eth_client, &client, args, diff --git a/apps/src/lib/cli/utils.rs b/apps/src/lib/cli/utils.rs index d937a249df..8c74b35393 100644 --- a/apps/src/lib/cli/utils.rs +++ b/apps/src/lib/cli/utils.rs @@ -3,17 +3,26 @@ use std::fmt::Debug; use std::io::Write; use std::marker::PhantomData; use std::str::FromStr; +use std::sync::Arc; use clap::{ArgAction, ArgMatches}; use color_eyre::eyre::Result; use data_encoding::HEXLOWER_PERMISSIVE; use namada::eth_bridge::ethers::core::k256::elliptic_curve::SecretKey as Secp256k1Sk; +use namada::eth_bridge::ethers::middleware::SignerMiddleware; +use namada::eth_bridge::ethers::providers::{Http, Middleware, Provider}; use namada::eth_bridge::ethers::signers::{Signer, Wallet}; use super::args; use super::context::{Context, FromContext}; use crate::cli::api::CliIo; +/// Environment variable where Ethereum relayer private +/// keys are stored. +// TODO: remove this in favor of getting eth keys from +// namadaw, ledger, or something more secure +const RELAYER_KEY_ENV_VAR: &str = "NAMADA_RELAYER_KEY"; + // We only use static strings pub type App = clap::Command; pub type ClapArg = clap::Arg; @@ -369,11 +378,8 @@ pub fn safe_exit(_: i32) -> ! { /// Load an Ethereum wallet from the environment. /// /// If no chain id is provided, Ethereum main net is assumed. -#[allow(dead_code)] -pub fn get_eth_signer_from_env(chain_id: Option) -> Option { - const RELAYER_KEY: &str = "NAMADA_RELAYER_KEY"; - - let relayer_key = std::env::var(RELAYER_KEY).ok()?; +fn get_eth_signer_from_env(chain_id: Option) -> Option { + let relayer_key = std::env::var(RELAYER_KEY_ENV_VAR).ok()?; let relayer_key = HEXLOWER_PERMISSIVE.decode(relayer_key.as_ref()).ok()?; let relayer_key = Secp256k1Sk::from_slice(&relayer_key).ok()?; @@ -382,3 +388,18 @@ pub fn get_eth_signer_from_env(chain_id: Option) -> Option { Some(wallet) } + +/// Return an Ethereum RPC client. +/// +/// If no chain id is provided, Ethereum main net is assumed. +pub fn get_eth_rpc_client( + url: &str, + chain_id: Option, +) -> Arc { + let client = Provider::::try_from(url) + .expect("Failed to instantiate Ethereum RPC client"); + let signer = get_eth_signer_from_env(chain_id).unwrap_or_else(|| { + panic!("Failed to get Ethereum key from {RELAYER_KEY_ENV_VAR} env var") + }); + Arc::new(SignerMiddleware::new(client, signer)) +} From 096536c9d494334ec353e79f4d22a6bb1b974573 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Fri, 20 Oct 2023 12:53:33 +0100 Subject: [PATCH 3/4] Query chain id to be used in the eth wallet --- apps/src/lib/cli/relayer.rs | 4 ++-- apps/src/lib/cli/utils.rs | 18 ++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/apps/src/lib/cli/relayer.rs b/apps/src/lib/cli/relayer.rs index 133930e8c0..f74ae1b5bf 100644 --- a/apps/src/lib/cli/relayer.rs +++ b/apps/src/lib/cli/relayer.rs @@ -73,7 +73,7 @@ impl CliApi { .await .proceed_or_else(error)?; let eth_client = - get_eth_rpc_client(&args.eth_rpc_endpoint, None); + get_eth_rpc_client(&args.eth_rpc_endpoint).await; let args = args.to_sdk_ctxless(); bridge_pool::relay_bridge_pool_proof::<_, _, IO>( eth_client, &client, args, @@ -188,7 +188,7 @@ impl CliApi { .await .proceed_or_else(error)?; let eth_client = - get_eth_rpc_client(&args.eth_rpc_endpoint, None); + get_eth_rpc_client(&args.eth_rpc_endpoint).await; let args = args.to_sdk_ctxless(); validator_set::relay_validator_set_update::<_, _, IO>( eth_client, &client, args, diff --git a/apps/src/lib/cli/utils.rs b/apps/src/lib/cli/utils.rs index 8c74b35393..9a44add694 100644 --- a/apps/src/lib/cli/utils.rs +++ b/apps/src/lib/cli/utils.rs @@ -376,28 +376,26 @@ pub fn safe_exit(_: i32) -> ! { } /// Load an Ethereum wallet from the environment. -/// -/// If no chain id is provided, Ethereum main net is assumed. -fn get_eth_signer_from_env(chain_id: Option) -> Option { +fn get_eth_signer_from_env(chain_id: u64) -> Option { let relayer_key = std::env::var(RELAYER_KEY_ENV_VAR).ok()?; let relayer_key = HEXLOWER_PERMISSIVE.decode(relayer_key.as_ref()).ok()?; let relayer_key = Secp256k1Sk::from_slice(&relayer_key).ok()?; let wallet: Wallet<_> = relayer_key.into(); - let wallet = wallet.with_chain_id(chain_id.unwrap_or(1)); + let wallet = wallet.with_chain_id(chain_id); Some(wallet) } /// Return an Ethereum RPC client. -/// -/// If no chain id is provided, Ethereum main net is assumed. -pub fn get_eth_rpc_client( - url: &str, - chain_id: Option, -) -> Arc { +pub async fn get_eth_rpc_client(url: &str) -> Arc { let client = Provider::::try_from(url) .expect("Failed to instantiate Ethereum RPC client"); + let chain_id = client + .get_chainid() + .await + .expect("Failed to query chain id") + .as_u64(); let signer = get_eth_signer_from_env(chain_id).unwrap_or_else(|| { panic!("Failed to get Ethereum key from {RELAYER_KEY_ENV_VAR} env var") }); From 8bec66e3dd7c8942341d9b4efc6f9cedc71518f9 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Fri, 20 Oct 2023 13:04:34 +0100 Subject: [PATCH 4/4] Changelog for #2012 --- .changelog/unreleased/improvements/2012-sign-eth-txs.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/unreleased/improvements/2012-sign-eth-txs.md diff --git a/.changelog/unreleased/improvements/2012-sign-eth-txs.md b/.changelog/unreleased/improvements/2012-sign-eth-txs.md new file mode 100644 index 0000000000..63dfa70870 --- /dev/null +++ b/.changelog/unreleased/improvements/2012-sign-eth-txs.md @@ -0,0 +1,2 @@ +- Sign transactions originating from the Namada relayer that are sent to + Ethereum ([\#2012](https://github.com/anoma/namada/pull/2012)) \ No newline at end of file