Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add etherscan api configuration #372

Merged
merged 7 commits into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,32 @@ webb-relayer -vv -c ./config
- [`SubstrateConfig`](https://webb-tools.github.io/relayer/webb_relayer/config/struct.SubstrateConfig.html)
- [`EvmChainConfig`](https://webb-tools.github.io/relayer/webb_relayer/config/struct.EvmChainConfig.html)

#### Relayer Common Configuration
| Field | Description | Optionality |
| -------------------------- | ------------------------------------------------------------------------------------------ | ----------- |
| `port` | Relayer port number | Required |
| `features` |Enable required features by setting them to `true` . All featured are enabled by default | Optional|
| `evm-etherscan` | Etherscan api configuration for chains, required if `private-tx` feature is enabled for relayer. | Optional |

- `Features` Configuration

```
[features]
governance-relay = true
data-query = true
private-tx-relay = true
```
- `Evm-etherscan` Configuration
```
[evm-etherscan.goerli]
chain-id = 5
api-key = "$ETHERSCAN_GOERLI_API_KEY"
[evm-etherscan.polygon]
chain-id = 137
api-key = "$POLYGONSCAN_MAINNET_API_KEY"
```


#### Chain Configuration

| Field | Description | Optionality |
Expand Down
22 changes: 22 additions & 0 deletions config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ following section we will describe the different configuration entries and how t
- [governance-relay](#governance-relay)
- [data-query](#data-query)
- [private-tx-relay](#private-tx-relay)
- [evm-etherscan](#evm-etherscan)
- [chain-id](#chain-id)
- [api-key](#api-key)

- [EVM Chain Configuration](#evm-chain-configuration)
- [name](#name)
- [chain-id](#chain-id)
Expand Down Expand Up @@ -168,6 +172,24 @@ Example:
[features]
private-tx-relay = true
```
#### evm-etherscan
Etherscan api configuration for chains. This config is required if [private-tx-relay](#private-tx-relay) is enabled.
example:
```toml
[evm-etherscan.goerli]
chain-id = 5
api-key = "$ETHERSCAN_GOERLI_API_KEY"
[evm-etherscan.polygon]
chain-id = 137
api-key = "$POLYGONSCAN_MAINNET_API_KEY"
```

#### api-key
Etherscan api key, this are used to fetch gas prices from the explorer.
example:
```toml
api-key = $ETHERSCAN_GOERLI_API_KEY
```

### EVM Chain Configuration

Expand Down
1 change: 1 addition & 0 deletions config/development/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ ATHENA_PRIVATE_KEY=${PRIVATE_KEY}
DEMETER_PRIVATE_KEY=${PRIVATE_KEY}

GOVERNOR_PRIVATE_KEY=0x0000000000000000000000000000000000000000000000000000000000000001
ETHERSCAN_API_KEY=YI7KXQGB98XXXXZJ5595E6Q7ZH2PGU32BG7
4 changes: 4 additions & 0 deletions config/development/evm-blanknet/main.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ port = 9955
[experimental]
smart-anchor-updates = false
smart-anchor-updates-retries = 3

[evm-etherscan.mainnet]
chain-id = 5001
api-key = "$ETHERSCAN_API_KEY"
9 changes: 9 additions & 0 deletions config/development/evm-local-tangle/main.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
port = 9955

[experimental]
smart-anchor-updates = false
smart-anchor-updates-retries = 3

[evm-etherscan.mainnet]
chain-id = 5001
api-key = "$ETHERSCAN_API_KEY"
2 changes: 1 addition & 1 deletion config/exclusive-strategies/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ OPTIMISM_TESTNET_WSS_URL=${EXAMPLE_WSS_URL}
OPTIMISM_TESTNET_PRIVATE_KEY=${EXAMPLE_PRIVATE_KEY}



ETHERSCAN_API_KEY=YI7KXQGB98XXXXZJ5595E6Q7ZH2PGU32BG7
MOCKED_BACKEND_KEY=${EXAMPLE_PRIVATE_KEY}
9 changes: 8 additions & 1 deletion config/exclusive-strategies/private-tx-relaying/main.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,11 @@ port = 9955
[features]
governance-relay = false
data-query = false
private-tx-relay = true
private-tx-relay = true

[evm-etherscan.goerli]
chain-id = 5
api-key = "$ETHERSCAN_API_KEY"
[evm-etherscan.sepolia]
chain-id = 11155111
api-key = "$ETHERSCAN_API_KEY"
15 changes: 15 additions & 0 deletions crates/relayer-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ use evm::EvmChainConfig;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use substrate::SubstrateConfig;
use webb::evm::ethers::types::Chain;
use webb_relayer_types::etherscan_api::EtherscanApiKey;

/// The default port the relayer will listen on. Defaults to 9955.
const fn default_port() -> u16 {
Expand Down Expand Up @@ -80,6 +82,9 @@ pub struct WebbRelayerConfig {
/// default to 9955
#[serde(default = "default_port", skip_serializing)]
pub port: u16,
/// Etherscan API key configuration for evm based chains.
#[serde(default)]
pub evm_etherscan: HashMap<Chain, EtherscanApiConfig>,
/// EVM based networks and the configuration.
///
/// a map between chain name and its configuration.
Expand Down Expand Up @@ -174,6 +179,16 @@ impl Default for FeaturesConfig {
}
}

/// Configuration to add etherscan API key
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct EtherscanApiConfig {
/// Chain Id
pub chain_id: u32,
/// A wrapper type around the `String` to allow reading it from the env.
pub api_key: EtherscanApiKey,
}

/// TxQueueConfig is the configuration for the TxQueue.
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
Expand Down
29 changes: 22 additions & 7 deletions crates/relayer-context/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
//! # Relayer Context Module 🕸️
//!
//! A module for managing the context of the relayer.
use std::convert::TryFrom;
use std::sync::Arc;
use std::time::Duration;
use std::{collections::HashMap, convert::TryFrom};

use tokio::sync::{broadcast, Mutex};

Expand Down Expand Up @@ -55,8 +55,8 @@ pub struct RelayerContext {
store: SledStore,
/// API client for https://www.coingecko.com/
coin_gecko_client: Arc<CoinGeckoClient>,
/// API client for https://etherscan.io/
etherscan_client: Client,
/// Hashmap of <ChainID, Etherscan Client>
etherscan_clients: HashMap<u32, Client>,
}

impl RelayerContext {
Expand All @@ -68,14 +68,20 @@ impl RelayerContext {
let (notify_shutdown, _) = broadcast::channel(2);
let metrics = Arc::new(Mutex::new(Metrics::new()));
let coin_gecko_client = Arc::new(CoinGeckoClient::default());
let etherscan_client = Client::new_from_env(Chain::Mainnet).unwrap();
let mut etherscan_clients: HashMap<u32, Client> = HashMap::new();
for (chain, etherscan_config) in config.evm_etherscan.iter() {
let client =
Client::new(*chain, etherscan_config.api_key.to_string())
.unwrap();
etherscan_clients.insert(etherscan_config.chain_id, client);
}
Self {
config,
notify_shutdown,
metrics,
store,
coin_gecko_client,
etherscan_client,
etherscan_clients,
}
}
/// Returns a broadcast receiver handle for the shutdown signal.
Expand Down Expand Up @@ -187,8 +193,17 @@ impl RelayerContext {
}

/// Returns API client for https://etherscan.io/
pub fn etherscan_client(&self) -> &Client {
&self.etherscan_client
pub fn etherscan_client(
&self,
chain_id: u32,
) -> webb_relayer_utils::Result<&Client> {
let client =
self.etherscan_clients.get(&chain_id).ok_or_else(|| {
webb_relayer_utils::Error::EtherscanConfigNotFound {
chain_id: chain_id.to_string(),
}
})?;
Ok(client)
}
}

Expand Down
66 changes: 66 additions & 0 deletions crates/relayer-types/src/etherscan_api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Serialize)]
pub struct EtherscanApiKey(String);

impl std::fmt::Debug for EtherscanApiKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("EtherscanApiKey").finish()
}
}

impl From<String> for EtherscanApiKey {
fn from(api_key: String) -> Self {
EtherscanApiKey(api_key)
}
}

impl std::ops::Deref for EtherscanApiKey {
type Target = String;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<'de> Deserialize<'de> for EtherscanApiKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct EtherscanApiKeyVisitor;
impl<'de> serde::de::Visitor<'de> for EtherscanApiKeyVisitor {
type Value = String;

fn expecting(
&self,
formatter: &mut std::fmt::Formatter,
) -> std::fmt::Result {
formatter.write_str(
"Etherscan api key or an env var containing a etherscan api key in it",
)
}

fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
if value.starts_with('$') {
// env
let var = value.strip_prefix('$').unwrap_or(value);
tracing::trace!("Reading {} from env", var);
let val = std::env::var(var).map_err(|e| {
serde::de::Error::custom(format!(
"error while loading this env {var}: {e}",
))
})?;
return Ok(val);
}
Ok(value.to_string())
}
}

let etherscan_api_key =
deserializer.deserialize_str(EtherscanApiKeyVisitor)?;
Ok(Self(etherscan_api_key))
}
}
1 change: 1 addition & 0 deletions crates/relayer-types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod dynamic_payload;
pub mod etherscan_api;
pub mod mnemonic;
pub mod private_key;
pub mod rpc_url;
Expand Down
6 changes: 6 additions & 0 deletions crates/relayer-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ pub enum Error {
/// Arkworks Errors.
#[error("{}", _0)]
ArkworksError(String),
/// Etherscan api configuration not found.
#[error("Etherscan api configuration not found for chain : {}", chain_id)]
EtherscanConfigNotFound {
/// The chain id of the node.
chain_id: String,
},
#[error("No bridge registered with DKG for resource id {:?}", _0)]
BridgeNotRegistered(ResourceId),
}
Expand Down
5 changes: 4 additions & 1 deletion crates/tx-relay/src/evm/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,10 @@ async fn generate_fee_info(
let wrapped_token_price = prices[&wrapped_token.0].usd.unwrap();

// Fetch native gas price estimate from etherscan.io, using "average" value
let gas_oracle = ctx.etherscan_client().gas_oracle().await?;
let gas_oracle = ctx
.etherscan_client(chain_id.underlying_chain_id())?
.gas_oracle()
.await?;
let gas_price_gwei = U256::from(gas_oracle.propose_gas_price);
let gas_price = parse_units(gas_price_gwei, "gwei")?.into();

Expand Down
22 changes: 22 additions & 0 deletions tests/lib/webbRelayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { padHexString } from '../lib/utils.js';

export type CommonConfig = {
features?: FeaturesConfig;
evmEtherscan?: EvmEtherscanConfig;
port: number;
};

Expand Down Expand Up @@ -76,6 +77,9 @@ export class WebbRelayer {
// Write the folder-wide configuration for this relayer instance
type WrittenCommonConfig = {
features?: ConvertToKebabCase<FeaturesConfig>;
'evm-etherscan'?: {
[key: string]: ConvertToKebabCase<EtherscanApiConfig>;
};
port: number;
};
const commonConfigFile: WrittenCommonConfig = {
Expand All @@ -84,6 +88,14 @@ export class WebbRelayer {
'governance-relay': opts.commonConfig.features?.governanceRelay ?? true,
'private-tx-relay': opts.commonConfig.features?.privateTxRelay ?? true,
},
'evm-etherscan': Object.fromEntries(
Object.entries(opts.commonConfig.evmEtherscan ?? {}).map(
([key, { chainId, apiKey }]) => [
key,
{ ...{ 'chain-id': chainId, 'api-key': apiKey } },
]
)
),
port: opts.commonConfig.port,
};
const configString = JSON.stringify(commonConfigFile, null, 2);
Expand Down Expand Up @@ -590,6 +602,16 @@ export interface FeaturesConfig {
governanceRelay?: boolean;
privateTxRelay?: boolean;
}

export interface EtherscanApiConfig {
chainId: number;
apiKey: string;
}

export interface EvmEtherscanConfig {
[key: string]: EtherscanApiConfig;
}

export interface WithdrawConfig {
withdrawFeePercentage: number;
withdrawGaslimit: `0x${string}`;
Expand Down
Loading