diff --git a/ethers-etherscan/src/errors.rs b/ethers-etherscan/src/errors.rs index 060b518f..2ff4d0c6 100644 --- a/ethers-etherscan/src/errors.rs +++ b/ethers-etherscan/src/errors.rs @@ -37,4 +37,13 @@ pub enum EtherscanError { MissingSolcVersion(String), #[error("Invalid API Key")] InvalidApiKey, + #[error("Sorry, you have been blocked by Cloudflare, See also https://community.cloudflare.com/t/sorry-you-have-been-blocked/110790")] + BlockedByCloudflare, +} + +/// etherscan/polyscan is protected by cloudflare, which can lead to html responses like `Sorry, you have been blocked` See also +/// +/// This returns true if the `txt` is a cloudflare error response +pub(crate) fn is_blocked_by_cloudflare_response(txt: &str) -> bool { + txt.to_lowercase().contains("sorry, you have been blocked") } diff --git a/ethers-etherscan/src/lib.rs b/ethers-etherscan/src/lib.rs index 1f08e0b0..33fd37cf 100644 --- a/ethers-etherscan/src/lib.rs +++ b/ethers-etherscan/src/lib.rs @@ -1,5 +1,6 @@ //! Bindings for [etherscan.io web api](https://docs.etherscan.io/) +use crate::errors::is_blocked_by_cloudflare_response; use contract::ContractMetadata; use errors::EtherscanError; use ethers_core::{ @@ -15,6 +16,7 @@ use std::{ time::{Duration, SystemTime, UNIX_EPOCH}, }; use tracing::{error, trace}; + pub mod account; pub mod contract; pub mod errors; @@ -168,10 +170,14 @@ impl Client { .text() .await?; - Ok(serde_json::from_str(&response).map_err(|err| { + serde_json::from_str(&response).map_err(|err| { error!(target: "etherscan", ?response, "Failed to deserialize response: {}", err); - err - })?) + if is_blocked_by_cloudflare_response(&response) { + EtherscanError::BlockedByCloudflare + } else { + EtherscanError::Serde(err) + } + }) } /// Execute an API GET request with parameters @@ -189,7 +195,11 @@ impl Client { let response: ResponseData = serde_json::from_str(&response).map_err(|err| { error!(target: "etherscan", ?response, "Failed to deserialize response: {}", err); - err + if is_blocked_by_cloudflare_response(&response) { + EtherscanError::BlockedByCloudflare + } else { + EtherscanError::Serde(err) + } })?; match response {