Skip to content

Commit

Permalink
Completely remove API tokens - allow users to add their own api tokens
Browse files Browse the repository at this point in the history
if the have one.
  • Loading branch information
JasoonS committed Jun 20, 2024
1 parent f57caf4 commit f271f7c
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 211 deletions.
241 changes: 39 additions & 202 deletions codegenerator/cli/src/config_parsing/chain_helpers.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::env;

use anyhow::anyhow;
use anyhow::Context;
use clap::ValueEnum;
Expand Down Expand Up @@ -333,246 +335,85 @@ impl Network {
}

pub enum BlockExplorerApi {
DefaultEthers {
api_key: Option<String>,
},
DefaultEthers,
Custom {
//eg. "https://gnosisscan.io/"
base_url: String,
//eg. "https://api.gnosisscan.io/api/"
api_url: String,
api_key: Option<String>,
},
}

impl BlockExplorerApi {
pub fn default_ethers(api_key: Option<String>) -> Self {
Self::DefaultEthers { api_key: api_key }
}

fn custom(base_url: &str, api_url: &str, maybe_api_key: Option<String>) -> Self {
fn custom(base_url: &str, api_url: &str) -> Self {
let base_url = format!("https://{}/", base_url);
let api_url = format!("https://{}/api/", api_url);
Self::Custom {
base_url,
api_url,
api_key: maybe_api_key,
}
Self::Custom { base_url, api_url }
}
}

impl NetworkWithExplorer {
// Function to return the chain ID of the network based on the network name
pub fn get_block_explorer_api(&self, rate_limit_retry_count: usize) -> BlockExplorerApi {
let api_keys = match self {
NetworkWithExplorer::EthereumMainnet => [
"9NNX6U3WXH8VWKSUCZYSYMH38A3Z9V925B",
"FBVF62I851WY2A3Z5GUP2M6KQWR3M196SJ",
"5GXXUX8RHG798TXASS8G9U6BRAAGM4SP7H",
],
NetworkWithExplorer::Goerli => [
"9NNX6U3WXH8VWKSUCZYSYMH38A3Z9V925B",
"FBVF62I851WY2A3Z5GUP2M6KQWR3M196SJ",
"5GXXUX8RHG798TXASS8G9U6BRAAGM4SP7H",
],
NetworkWithExplorer::Holesky => [
"9NNX6U3WXH8VWKSUCZYSYMH38A3Z9V925B",
"FBVF62I851WY2A3Z5GUP2M6KQWR3M196SJ",
"5GXXUX8RHG798TXASS8G9U6BRAAGM4SP7H",
],
NetworkWithExplorer::Optimism => [
"ZWBZ1HIDFC5GCUUWSPHUFMYY9FZI7BTD5Y",
"MCZM3IWFFBTJYZNYFEDGXS4NKQMW19G8H8",
"YSYDI8FPNKGDDQU5349NWCVCQKI164IRBD",
],
NetworkWithExplorer::Bsc => [
"9YEBZHXJW7Q9RCRHHXRFJEQ4X2YIQ7D6PI",
"G5NFVBPX2QHPUAPBU91RBW9AEYJDWNTIJ7",
"VKW31ERMD1K97NWDC45Y8MWC2YSA3DVY4M",
],
NetworkWithExplorer::Polygon => [
"7KQZVW13K3VU2SAIUVNHG4M3HPTMHD9T7Z",
"YCIATTDSTMJXNNMTUWFJS3ZMG83DJ7U3N2",
"UXZJ3U5QBZIK161QJDCM8WDVTKRZ7KTG9K",
],
NetworkWithExplorer::OptimismGoerli => [
"ZWBZ1HIDFC5GCUUWSPHUFMYY9FZI7BTD5Y",
"MCZM3IWFFBTJYZNYFEDGXS4NKQMW19G8H8",
"YSYDI8FPNKGDDQU5349NWCVCQKI164IRBD",
],
NetworkWithExplorer::OptimismSepolia => [
"ZWBZ1HIDFC5GCUUWSPHUFMYY9FZI7BTD5Y",
"MCZM3IWFFBTJYZNYFEDGXS4NKQMW19G8H8",
"YSYDI8FPNKGDDQU5349NWCVCQKI164IRBD",
],
NetworkWithExplorer::ArbitrumOne => [
"3T4HN3KASB3IPQEZX21A9EXFFDKBNIRQ3R",
"F3VXQYQSV2IKB8UCMNASMPWP39GAN8JDFY",
"G65DZIAMA9756ZS875UDBFY6UH4W5VJ5DW",
],
NetworkWithExplorer::ArbitrumGoerli => [
"3T4HN3KASB3IPQEZX21A9EXFFDKBNIRQ3R",
"F3VXQYQSV2IKB8UCMNASMPWP39GAN8JDFY",
"G65DZIAMA9756ZS875UDBFY6UH4W5VJ5DW",
],
NetworkWithExplorer::ArbitrumSepolia => [
"3T4HN3KASB3IPQEZX21A9EXFFDKBNIRQ3R",
"F3VXQYQSV2IKB8UCMNASMPWP39GAN8JDFY",
"G65DZIAMA9756ZS875UDBFY6UH4W5VJ5DW",
],
NetworkWithExplorer::ArbitrumNova => [
"3T4HN3KASB3IPQEZX21A9EXFFDKBNIRQ3R",
"F3VXQYQSV2IKB8UCMNASMPWP39GAN8JDFY",
"G65DZIAMA9756ZS875UDBFY6UH4W5VJ5DW",
],
NetworkWithExplorer::Mumbai => [
"7KQZVW13K3VU2SAIUVNHG4M3HPTMHD9T7Z",
"YCIATTDSTMJXNNMTUWFJS3ZMG83DJ7U3N2",
"UXZJ3U5QBZIK161QJDCM8WDVTKRZ7KTG9K",
],
NetworkWithExplorer::Sepolia => [
"9NNX6U3WXH8VWKSUCZYSYMH38A3Z9V925B",
"FBVF62I851WY2A3Z5GUP2M6KQWR3M196SJ",
"5GXXUX8RHG798TXASS8G9U6BRAAGM4SP7H",
],
NetworkWithExplorer::Gnosis => [
"BYHU1N8Y1R3J9H5VA9DN3K7NDIIESYW9JY",
"9CI9358SI6SY8YRM6QDMCRRUGG4T72VT1A",
"8TC268FB21VFAKN6S5VXKHKQTM2FJGAYYX",
],
NetworkWithExplorer::Linea => [
"PVMK8H27KU5GH43T3TXM8AV66TP3ZDUNIF",
"6JG3C8ACZGAAXDH575MQ4D1FEFTZ881GY3",
"XIB1FPBWBFWVWBJU6Q1TCSJ2NXEB5SGUBW",
],
NetworkWithExplorer::Base => [
"X5NZKY2RDIX8KVDDATSUY56HAKYS2QR44N",
"SP77NC1P7IX1ZJJW327IZYXKAX8QB9XJMN",
"Z564GWWJGQ7PFC8FAPMMASZ6QZZAPNTT5X",
],
NetworkWithExplorer::BaseSepolia => [
"X5NZKY2RDIX8KVDDATSUY56HAKYS2QR44N",
"SP77NC1P7IX1ZJJW327IZYXKAX8QB9XJMN",
"Z564GWWJGQ7PFC8FAPMMASZ6QZZAPNTT5X",
],
NetworkWithExplorer::Scroll => [
"5747W9V9U5TB71SEQVJ1MV488ZKUPRDY5P",
"NGTI7FCEWXB9S8QYU96PV94VYWN3K3SU6I",
"DAM7Q5P727XZ8D4QX5TFTDDVJBSATS6G38",
],
NetworkWithExplorer::PolygonZkevm => [
"CC63UV4JWQY4ZJ4Q3FUBGNWKV7NUX6HDW7",
"EW6D5AUVNJXAQRHBX3ZDKQGK6M99MP8J9T",
"68JQBIHK1ANMHVBK8EEGKQDK7H2K9YCD2V",
],
NetworkWithExplorer::Celo => [
"RBX9BZBUYIDTZHR6ESSK1JMVC34FDU7KK8",
"Y9AHMQWF1Z4H1CPT3MCP36Q2X9VVF4CT8S",
"JGWV53QKINTW3SRJSJ9V6SJ9KDUYZXMAA8",
],
NetworkWithExplorer::Kroma => [
"9V3VRR1N8293VBBVXNQ4HS6Z6HSJ4KWQPK",
"JG6CDQYK7CQWAXDBF1M4N84PW12PCXNRVV",
"RURK915VJUAB7W6T5U3JYHQ3R9ZFIN7JEB",
],
NetworkWithExplorer::Moonbeam => [
"E6CBETQ1UWJXI54Q5SVBDB9F91ZB45PVRG",
"CNWU4T5RCN31JUK99HR4P4XV2EUEVQ7P62",
"TGUAN47MYKD8F5RWW66NT8RZSQYRUNGEWH",
],
NetworkWithExplorer::Fantom => [
"VFWQXQVIZ9GN7IAWNAS8RZKNV9DEUX179Z",
"INIU3I5SNKAVJ8NZB1VVMXW8TNCGQ38AE7",
"ZMBT883ZBZDZQ5SWKZADDKTB1E7P3JCZHD",
],
NetworkWithExplorer::Blast => [
"FU5IBP7AV7JY22DTTUJZS1IZEYY55BNWQR",
"513XRZID5JBCANQG6KEQAKR97PN1D4BW7K",
"87UU1RQE6D1YNIG2AWD3BV9UKICHVE4S4B",
],
NetworkWithExplorer::BlastSepolia => [
"FU5IBP7AV7JY22DTTUJZS1IZEYY55BNWQR",
"513XRZID5JBCANQG6KEQAKR97PN1D4BW7K",
"87UU1RQE6D1YNIG2AWD3BV9UKICHVE4S4B",
],
};

// Selecting the api_key to be used based on the index
let api_key: Option<String> = if rate_limit_retry_count == 0 {
// If it is the first try, don't use any api key (usually it isn't required unless api
// is hit frequently).
None
} else {
// Retrieving the index of the api_key to be used based on the rate_limit_retry_count
let api_key_index = rate_limit_retry_count % api_keys.len();
Some(api_keys[api_key_index].to_string())
};

//Define all custom block explorer definitions at the top otherwise default with ethers api
pub fn get_block_explorer_api(&self) -> BlockExplorerApi {
match self {
NetworkWithExplorer::Celo => {
BlockExplorerApi::custom("celoscan.io", "api.celoscan.io", api_key)
}
NetworkWithExplorer::Celo => BlockExplorerApi::custom("celoscan.io", "api.celoscan.io"),
NetworkWithExplorer::Gnosis => {
BlockExplorerApi::custom("gnosisscan.io", "api.gnosisscan.io", api_key)
BlockExplorerApi::custom("gnosisscan.io", "api.gnosisscan.io")
}
NetworkWithExplorer::Holesky => {
BlockExplorerApi::custom("holesky.etherscan.io", "api-holesky.etherscan.io")
}
NetworkWithExplorer::Holesky => BlockExplorerApi::custom(
"holesky.etherscan.io",
"api-holesky.etherscan.io",
api_key,
),
NetworkWithExplorer::Scroll => {
BlockExplorerApi::custom("scrollscan.com", "api.scrollscan.com", api_key)
BlockExplorerApi::custom("scrollscan.com", "api.scrollscan.com")
}
NetworkWithExplorer::ArbitrumSepolia => {
BlockExplorerApi::custom("sepolia.arbiscan.io", "api-sepolia.arbiscan.io", api_key)
BlockExplorerApi::custom("sepolia.arbiscan.io", "api-sepolia.arbiscan.io")
}
NetworkWithExplorer::Kroma => {
BlockExplorerApi::custom("kromascan.com", "api.kromascan.com", api_key)
BlockExplorerApi::custom("kromascan.com", "api.kromascan.com")
}
NetworkWithExplorer::BaseSepolia => {
BlockExplorerApi::custom("sepolia.basescan.org", "api-sepolia.basescan.org")
}
NetworkWithExplorer::BaseSepolia => BlockExplorerApi::custom(
"sepolia.basescan.org",
"api-sepolia.basescan.org",
api_key,
),
NetworkWithExplorer::OptimismSepolia => BlockExplorerApi::custom(
"sepolia-optimistic.etherscan.io",
"api-sepolia-optimistic.etherscan.io",
api_key,
),
NetworkWithExplorer::Blast => {
BlockExplorerApi::custom("blastscan.io", "api.blastscan.io", api_key)
BlockExplorerApi::custom("blastscan.io", "api.blastscan.io")
}
NetworkWithExplorer::BlastSepolia => {
BlockExplorerApi::custom("blastscan.io", "api-testnet.blastscan.io", api_key)
BlockExplorerApi::custom("blastscan.io", "api-testnet.blastscan.io")
}
_ => BlockExplorerApi::default_ethers(api_key),
_ => BlockExplorerApi::DefaultEthers,
}
}

pub fn get_env_token_name(&self) -> String {
let name = format!("{:?}", self); // Converts enum variant to string
let name = name.replace("NetworkWithExplorer::", ""); // Remove the enum type prefix
let name = name.replace("-", "_"); // Replace hyphens with underscores
let name = name.to_uppercase(); // Convert to uppercase
format!("{}_VERIFIED_CONTRACT_API_TOKEN", name)
}
}

pub fn get_etherscan_client(
network: &NetworkWithExplorer,
rate_limit_retry_count: usize,
) -> anyhow::Result<etherscan::Client> {
let client = match network.get_block_explorer_api(rate_limit_retry_count) {
BlockExplorerApi::DefaultEthers { api_key } => {
let chain_id = Network::from(*network).get_network_id();
pub fn get_etherscan_client(network: &NetworkWithExplorer) -> anyhow::Result<etherscan::Client> {
// Try to get the API token from the environment variable
let maybe_api_key = env::var(network.get_env_token_name());

let client = match network.get_block_explorer_api() {
BlockExplorerApi::DefaultEthers => {
let chain_id = Network::from(*network).get_network_id();
let ethers_chain = ethers::types::Chain::try_from(chain_id)
.context("Failed converting network with explorer id to ethers chain")?;

// The api doesn't allow not passing in an api key, but a
// blank string is allowed
etherscan::Client::new(ethers_chain, api_key.unwrap_or("".to_string()))
etherscan::Client::new(ethers_chain, maybe_api_key.unwrap_or("".to_string()))
.context("Failed creating client for network")?
}

BlockExplorerApi::Custom {
base_url,
api_url,
api_key,
} => {
BlockExplorerApi::Custom { base_url, api_url } => {
let mut builder = etherscan::Client::builder()
.with_url(&base_url)
.context(format!(
Expand All @@ -585,7 +426,7 @@ pub fn get_etherscan_client(
api_url
))?;

if let Some(key) = api_key {
if let Ok(key) = maybe_api_key {
builder = builder.with_api_key(&key);
}

Expand Down Expand Up @@ -614,10 +455,7 @@ mod test {
#[test]
fn all_networks_with_explorer_can_get_etherscan_client() {
for network in NetworkWithExplorer::iter() {
// Test with 4 rate limit retries as we have 3 api keys per network and wanted to validate the correct rotation
for rate_limit_retry_count in 0..4 {
get_etherscan_client(&network, rate_limit_retry_count).unwrap();
}
get_etherscan_client(&network).unwrap();
}
}

Expand Down Expand Up @@ -704,8 +542,7 @@ mod test {
async fn check_gnosis_get_contract_source_code() {
tracing_subscriber::fmt::init();
let network: NetworkWithExplorer = NetworkWithExplorer::Gnosis;
let rate_limit_retry_count = 0;
let client = get_etherscan_client(&network, rate_limit_retry_count).unwrap();
let client = get_etherscan_client(&network).unwrap();

client
.contract_source_code(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ async fn fetch_get_source_code_result_from_block_explorer(
) -> anyhow::Result<etherscan::contract::Metadata> {
//todo make retryable
let mut refetch_delay = Duration::from_secs(2);
let mut rate_limit_retry_count = 0;

let fail_if_maximum_is_exceeded =
|current_refetch_delay: Duration, e: EtherscanError| -> anyhow::Result<()> {
Expand All @@ -125,18 +124,25 @@ async fn fetch_get_source_code_result_from_block_explorer(
};

let contract_metadata: ContractMetadata = loop {
let client = chain_helpers::get_etherscan_client(network, rate_limit_retry_count)
let client = chain_helpers::get_etherscan_client(network)
.context("Making client for getting source code")?;

match client.contract_source_code(address.clone()).await {
Ok(res) => {
break Ok::<_, anyhow::Error>(res);
}
Err(e) => {
// In this case, increment the key index to use the next API key
// replace 3 with the number of API keys constant
if let EtherscanError::RateLimitExceeded = e {
rate_limit_retry_count += 1;
eprintln!(
"Rate limit hit. Retrying in {} seconds. You can try use your own API key by setting the {} environment variable if you are being rate limited or blocked.",
refetch_delay.as_secs(),
network.get_env_token_name()
);
fail_if_maximum_is_exceeded(refetch_delay, EtherscanError::RateLimitExceeded)?;




} else {
let retry_err = match e {
//In these cases, return ok(err) if it should be retried
Expand Down Expand Up @@ -167,9 +173,9 @@ async fn fetch_get_source_code_result_from_block_explorer(
| EtherscanError::PageNotFound => Err(e),
}?;
fail_if_maximum_is_exceeded(refetch_delay, retry_err)?;
tokio::time::sleep(refetch_delay).await;
refetch_delay *= 2;
}
}
tokio::time::sleep(refetch_delay).await;
refetch_delay *= 2;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion codegenerator/cli/src/hbs_templating/hbs_dir_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct HandleBarsDirGenerator<'a, T: Serialize> {
templates_dir: &'a RelativeDir<'a>,
rs_template: &'a T,
output_dir: &'a Path,
}
}

impl<'a, T: Serialize> HandleBarsDirGenerator<'a, T> {
pub fn new(templates_dir: &'a RelativeDir, rs_template: &'a T, output_dir: &'a Path) -> Self {
Expand Down

0 comments on commit f271f7c

Please sign in to comment.