From c0eb82b20a179fd443531ec3d5a4c14e3bf42786 Mon Sep 17 00:00:00 2001 From: James Hinshelwood Date: Mon, 29 Jul 2024 20:34:37 +0100 Subject: [PATCH] Fix `DifferentChainID` error PR #699 attempted to remove the startup-time dependency on the API by moving the point at which we get the chain ID to transaction creation time. However, this wasn't valid because the signer needs to be configured with the correct chain ID. Instead, we wrap our provider in a `tokio::sync::OnceCell` and lazily initialise it. This means the signer is initialised with the result of the call from `eth_chainId`, but we don't need to make this call until someone uses the faucet. --- products/eth-spout/src/main.rs | 50 +++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/products/eth-spout/src/main.rs b/products/eth-spout/src/main.rs index 2991d0762..01b284d3e 100644 --- a/products/eth-spout/src/main.rs +++ b/products/eth-spout/src/main.rs @@ -14,11 +14,11 @@ use ethers::{ middleware::{signer::SignerMiddlewareError, SignerMiddleware}, providers::{Http, Middleware, Provider}, signers::LocalWallet, - types::{Address, TransactionRequest, H256}, + types::{Address, TransactionRequest, H160, H256}, utils::{parse_checksummed, parse_ether, to_checksum, ConversionError, WEI_IN_ETHER}, }; use serde::Deserialize; -use tokio::sync::Mutex; +use tokio::sync::{Mutex, OnceCell}; #[derive(Template)] #[template(path = "home.html")] @@ -36,11 +36,20 @@ enum RequestStatus { AddrErr(anyhow::Error), SendErr(SignerMiddlewareError, LocalWallet>), RateLimitErr(Duration), + ConfigErr(anyhow::Error), } -async fn home_inner(State(state): State>, status: Option) -> Home { +async fn home_inner(State(state): State>, mut status: Option) -> Home { + let addr = match state.provider().await { + Ok(p) => p.address(), + Err(e) => { + eprintln!("{e:?}"); + status = Some(RequestStatus::ConfigErr(e)); + H160::zero() + } + }; Home { - from_addr: to_checksum(&state.provider.address(), None), + from_addr: to_checksum(&addr, None), native_token_symbol: state.config.native_token_symbol.clone(), amount: state.config.eth_amount.clone(), explorer_url: state.config.explorer_url.clone(), @@ -55,6 +64,7 @@ async fn home_inner(State(state): State>, status: Option Some(format!("Spout is misconfigured: {e:?}")), _ => None, }, } @@ -150,16 +160,17 @@ async fn request(State(state): State>, Form(request): Form c, + let provider = match state.provider().await { + Ok(p) => p, Err(e) => { eprintln!("{e:?}"); - return home_inner(State(state.clone()), Some(RequestStatus::SendErr(e))).await; + return home_inner(State(state.clone()), Some(RequestStatus::ConfigErr(e))).await; } }; - let tx = TransactionRequest::pay(address, value).chain_id(chain_id.low_u64()); - let status = match state.provider.send_transaction(tx, None).await { + + let value = parse_ether(&state.config.eth_amount).unwrap_or(WEI_IN_ETHER); + let tx = TransactionRequest::pay(address, value); + let status = match provider.send_transaction(tx, None).await { Ok(t) => RequestStatus::Sent(t.tx_hash()), Err(e) => { eprintln!("{e:?}"); @@ -217,22 +228,29 @@ impl Config { } struct AppState { - provider: SignerMiddleware, LocalWallet>, + provider: OnceCell, LocalWallet>>, config: Config, last_request: Mutex>, } +impl AppState { + async fn provider(&self) -> Result<&SignerMiddleware, LocalWallet>> { + let provider = Provider::try_from(&self.config.rpc_url)?; + let wallet: LocalWallet = self.config.private_key.parse()?; + Ok(self + .provider + .get_or_try_init(|| SignerMiddleware::new_with_provider_chain(provider, wallet)) + .await?) + } +} + #[tokio::main] async fn main() -> Result<()> { let config = Config::from_env()?; - let provider = Provider::try_from(&config.rpc_url)?; - let wallet: LocalWallet = config.private_key.parse()?; - let provider = SignerMiddleware::new(provider, wallet); - let addr = ("0.0.0.0".parse::()?, config.http_port); let state = Arc::new(AppState { - provider, + provider: OnceCell::new(), config, last_request: Default::default(), });