Skip to content

Commit 4107bb2

Browse files
Fix DifferentChainID error (#722)
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.
1 parent f054882 commit 4107bb2

File tree

1 file changed

+34
-16
lines changed

1 file changed

+34
-16
lines changed

products/eth-spout/src/main.rs

+34-16
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ use ethers::{
1414
middleware::{signer::SignerMiddlewareError, SignerMiddleware},
1515
providers::{Http, Middleware, Provider},
1616
signers::LocalWallet,
17-
types::{Address, TransactionRequest, H256},
17+
types::{Address, TransactionRequest, H160, H256},
1818
utils::{parse_checksummed, parse_ether, to_checksum, ConversionError, WEI_IN_ETHER},
1919
};
2020
use serde::Deserialize;
21-
use tokio::sync::Mutex;
21+
use tokio::sync::{Mutex, OnceCell};
2222

2323
#[derive(Template)]
2424
#[template(path = "home.html")]
@@ -36,11 +36,20 @@ enum RequestStatus {
3636
AddrErr(anyhow::Error),
3737
SendErr(SignerMiddlewareError<Provider<Http>, LocalWallet>),
3838
RateLimitErr(Duration),
39+
ConfigErr(anyhow::Error),
3940
}
4041

41-
async fn home_inner(State(state): State<Arc<AppState>>, status: Option<RequestStatus>) -> Home {
42+
async fn home_inner(State(state): State<Arc<AppState>>, mut status: Option<RequestStatus>) -> Home {
43+
let addr = match state.provider().await {
44+
Ok(p) => p.address(),
45+
Err(e) => {
46+
eprintln!("{e:?}");
47+
status = Some(RequestStatus::ConfigErr(e));
48+
H160::zero()
49+
}
50+
};
4251
Home {
43-
from_addr: to_checksum(&state.provider.address(), None),
52+
from_addr: to_checksum(&addr, None),
4453
native_token_symbol: state.config.native_token_symbol.clone(),
4554
amount: state.config.eth_amount.clone(),
4655
explorer_url: state.config.explorer_url.clone(),
@@ -55,6 +64,7 @@ async fn home_inner(State(state): State<Arc<AppState>>, status: Option<RequestSt
5564
"Request made too recently, please wait {} seconds before trying again",
5665
d.as_secs()
5766
)),
67+
Some(RequestStatus::ConfigErr(e)) => Some(format!("Spout is misconfigured: {e:?}")),
5868
_ => None,
5969
},
6070
}
@@ -150,16 +160,17 @@ async fn request(State(state): State<Arc<AppState>>, Form(request): Form<Request
150160
}
151161
}
152162

153-
let value = parse_ether(&state.config.eth_amount).unwrap_or(WEI_IN_ETHER);
154-
let chain_id = match state.provider.get_chainid().await {
155-
Ok(c) => c,
163+
let provider = match state.provider().await {
164+
Ok(p) => p,
156165
Err(e) => {
157166
eprintln!("{e:?}");
158-
return home_inner(State(state.clone()), Some(RequestStatus::SendErr(e))).await;
167+
return home_inner(State(state.clone()), Some(RequestStatus::ConfigErr(e))).await;
159168
}
160169
};
161-
let tx = TransactionRequest::pay(address, value).chain_id(chain_id.low_u64());
162-
let status = match state.provider.send_transaction(tx, None).await {
170+
171+
let value = parse_ether(&state.config.eth_amount).unwrap_or(WEI_IN_ETHER);
172+
let tx = TransactionRequest::pay(address, value);
173+
let status = match provider.send_transaction(tx, None).await {
163174
Ok(t) => RequestStatus::Sent(t.tx_hash()),
164175
Err(e) => {
165176
eprintln!("{e:?}");
@@ -217,22 +228,29 @@ impl Config {
217228
}
218229

219230
struct AppState {
220-
provider: SignerMiddleware<Provider<Http>, LocalWallet>,
231+
provider: OnceCell<SignerMiddleware<Provider<Http>, LocalWallet>>,
221232
config: Config,
222233
last_request: Mutex<HashMap<Address, Instant>>,
223234
}
224235

236+
impl AppState {
237+
async fn provider(&self) -> Result<&SignerMiddleware<Provider<Http>, LocalWallet>> {
238+
let provider = Provider::try_from(&self.config.rpc_url)?;
239+
let wallet: LocalWallet = self.config.private_key.parse()?;
240+
Ok(self
241+
.provider
242+
.get_or_try_init(|| SignerMiddleware::new_with_provider_chain(provider, wallet))
243+
.await?)
244+
}
245+
}
246+
225247
#[tokio::main]
226248
async fn main() -> Result<()> {
227249
let config = Config::from_env()?;
228250

229-
let provider = Provider::try_from(&config.rpc_url)?;
230-
let wallet: LocalWallet = config.private_key.parse()?;
231-
let provider = SignerMiddleware::new(provider, wallet);
232-
233251
let addr = ("0.0.0.0".parse::<IpAddr>()?, config.http_port);
234252
let state = Arc::new(AppState {
235-
provider,
253+
provider: OnceCell::new(),
236254
config,
237255
last_request: Default::default(),
238256
});

0 commit comments

Comments
 (0)