diff --git a/crates/autopilot/src/solvable_orders.rs b/crates/autopilot/src/solvable_orders.rs index 79695339a8..5d6fe4549f 100644 --- a/crates/autopilot/src/solvable_orders.rs +++ b/crates/autopilot/src/solvable_orders.rs @@ -717,7 +717,11 @@ async fn find_unsupported_tokens( match bad_token.detect(token).await { Ok(quality) => (!quality.is_good()).then_some(token), Err(err) => { - tracing::warn!(?token, ?err, "unable to determine token quality"); + tracing::warn!( + ?token, + ?err, + "unable to determine token quality, assume good" + ); Some(token) } } diff --git a/crates/shared/src/bad_token/instrumented.rs b/crates/shared/src/bad_token/instrumented.rs index 5979728881..ec9a4029bd 100644 --- a/crates/shared/src/bad_token/instrumented.rs +++ b/crates/shared/src/bad_token/instrumented.rs @@ -3,6 +3,7 @@ use { anyhow::Result, prometheus::IntCounterVec, prometheus_metric_storage::MetricStorage, + tracing::Instrument, }; pub trait InstrumentedBadTokenDetectorExt { @@ -33,7 +34,14 @@ pub struct InstrumentedBadTokenDetector { #[async_trait::async_trait] impl BadTokenDetecting for InstrumentedBadTokenDetector { async fn detect(&self, token: ethcontract::H160) -> Result { - let result = self.inner.detect(token).await; + let result = self + .inner + .detect(token) + .instrument(tracing::info_span!( + "token_quality", + token = format!("{token:#x}") + )) + .await; let label = match &result { Ok(TokenQuality::Good) => "good", diff --git a/crates/shared/src/bad_token/trace_call.rs b/crates/shared/src/bad_token/trace_call.rs index e4aa74409f..56812bc4bd 100644 --- a/crates/shared/src/bad_token/trace_call.rs +++ b/crates/shared/src/bad_token/trace_call.rs @@ -3,10 +3,16 @@ use { crate::{ethrpc::Web3, trace_many}, anyhow::{bail, ensure, Context, Result}, contracts::ERC20, - ethcontract::{dyns::DynTransport, transaction::TransactionBuilder, PrivateKey}, + ethcontract::{ + dyns::DynTransport, + jsonrpc::ErrorCode, + transaction::TransactionBuilder, + PrivateKey, + }, primitive_types::{H160, U256}, std::{cmp, sync::Arc}, web3::{ + error::TransportError, signing::keccak256, types::{BlockTrace, CallRequest, Res}, }, @@ -73,9 +79,31 @@ impl TraceCallDetector { // implementation sending to an address that does not have any balance // yet (implicitly 0) causes an allocation. let request = self.create_trace_request(token, amount, take_from); - let traces = trace_many::trace_many(request, &self.web3) - .await - .context("trace_many")?; + let traces = match trace_many::trace_many(request, &self.web3).await { + Ok(result) => result, + Err(e) => { + // If the node doesn't support trace calls, consider the token as good to not + // block the system + if matches!( + e, + web3::Error::Rpc(ethcontract::jsonrpc::Error { + code: ErrorCode::MethodNotFound, + .. + }) + ) || matches!( + e, + // Alchemy specific error + web3::Error::Transport(TransportError::Message(ref msg)) if msg == "HTTP error 400 Bad Request" + ) { + tracing::warn!( + error=?e, + "unable to perform trace call with configured node, assume good quality" + ); + return Ok(TokenQuality::Good); + } + return Err(e).context("trace_many"); + } + }; Self::handle_response(&traces, amount, take_from) } @@ -663,7 +691,7 @@ mod tests { UniswapV3Finder::new( IUniswapV3Factory::deployed(&web3).await.unwrap(), base_tokens.to_vec(), - FeeValues::Dynamic, + FeeValues::Static, ) .await .unwrap(), diff --git a/crates/shared/src/trace_many.rs b/crates/shared/src/trace_many.rs index 7ddc7ffacc..53401921bd 100644 --- a/crates/shared/src/trace_many.rs +++ b/crates/shared/src/trace_many.rs @@ -3,6 +3,7 @@ use { anyhow::{Context, Result}, web3::{ types::{BlockNumber, BlockTrace, CallRequest, TraceType}, + Error, Transport, }, }; @@ -10,7 +11,7 @@ use { // Use the trace_callMany api https://openethereum.github.io/JSONRPC-trace-module#trace_callmany // api to simulate these call requests applied together one after another. // Err if communication with the node failed. -pub async fn trace_many(requests: Vec, web3: &Web3) -> Result> { +pub async fn trace_many(requests: Vec, web3: &Web3) -> Result, Error> { let transport = web3.transport(); let requests = requests .into_iter() @@ -20,17 +21,15 @@ pub async fn trace_many(requests: Vec, web3: &Web3) -> Result>>()?; + .collect::>>() + .map_err(|e| Error::Decoder(e.to_string()))?; let block = BlockNumber::Latest; let params = vec![ serde_json::to_value(requests)?, serde_json::to_value(block)?, ]; - let response = transport - .execute("trace_callMany", params) - .await - .context("trace_callMany failed")?; - serde_json::from_value(response).context("failed to decode trace_callMany response") + let response = transport.execute("trace_callMany", params).await?; + serde_json::from_value(response).map_err(|e| Error::Decoder(e.to_string())) } // Check the return value of trace_many for whether all top level transactions