Skip to content
This repository has been archived by the owner on Aug 2, 2024. It is now read-only.

Commit

Permalink
Added oracle config
Browse files Browse the repository at this point in the history
  • Loading branch information
azurwastaken committed Jun 19, 2024
1 parent c9d769e commit 081939b
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 21 deletions.
101 changes: 101 additions & 0 deletions crates/client/eth-client/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub const DEFAULT_CHAIN_ID: u64 = 31337;
/// PRE_PRIVATE=$(jq -r '.private_keys[0]' $BUILD_DIR/anvil.json)
pub const DEFAULT_PRIVATE_KEY: &str = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";

pub const DEFAULT_API_URL: &str = "https://api.dev.pragma.build/node/v1/data/";

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct EthereumClientConfig {
#[serde(default)]
Expand All @@ -37,6 +39,8 @@ pub struct EthereumClientConfig {
pub wallet: Option<EthereumWalletConfig>,
#[serde(default)]
pub contracts: StarknetContracts,
#[serde(default)]
pub oracle: OracleConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -70,6 +74,82 @@ pub struct HttpProviderConfig {
pub gas_price_poll_ms: Option<u64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum OracleConfig {
Pragma(PragmaOracle),
}

impl OracleConfig {
pub fn get_fetch_url(&self, base: String, quote: String) -> String {
match self {
OracleConfig::Pragma(pragma_oracle) => pragma_oracle.get_fetch_url(base, quote),
}
}

pub fn get_api_key(&self) -> &String {
match self {
OracleConfig::Pragma(oracle) => &oracle.api_key,
}
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PragmaOracle {
#[serde(default = "default_api_url")]
pub api_url: String,
#[serde(default)]
pub api_key: String,
#[serde(default)]
pub aggregation_method: AggregationMethod,
#[serde(default)]
pub interval: Interval,
}

impl PragmaOracle {
fn get_fetch_url(&self, base: String, quote: String) -> String {
format!(
"{}{}/{}?interval={:?}&aggregation={:?}",
self.api_url, base, quote, self.interval, self.aggregation_method
)
}
}

#[derive(Default, Debug, Serialize, Deserialize, Clone, Copy)]
pub enum AggregationMethod {
#[serde(rename = "median")]
#[default]
Median,
#[serde(rename = "mean")]
Mean,
#[serde(rename = "twap")]
Twap,
}

// impl fmt::Display for AggregationMethod {
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// match self {
// AggregationMethod::Median => write!(f, "median"),
// AggregationMethod::Mean => write!(f, "mean"),
// AggregationMethod::Twap => write!(f, "twap"),
// }
// }
// }

// Supported Aggregation Intervals
#[derive(Default, Debug, Serialize, Deserialize, Clone, Copy)]
pub enum Interval {
#[serde(rename = "1min")]
#[default]
OneMinute,
#[serde(rename = "15min")]
FifteenMinutes,
#[serde(rename = "1h")]
OneHour,
#[serde(rename = "2h")]
TwoHours,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalWalletConfig {
#[serde(default = "default_chain_id")]
Expand All @@ -82,6 +162,10 @@ fn default_rpc_endpoint() -> String {
DEFAULT_RPC_ENDPOINT.into()
}

fn default_api_url() -> String {
DEFAULT_API_URL.into()
}

fn default_chain_id() -> u64 {
DEFAULT_CHAIN_ID
}
Expand All @@ -90,6 +174,23 @@ fn default_private_key() -> String {
DEFAULT_PRIVATE_KEY.to_string()
}

impl Default for PragmaOracle {
fn default() -> Self {
Self {
api_url: default_api_url(),
api_key: String::from(""),
aggregation_method: AggregationMethod::Median,
interval: Interval::OneMinute,
}
}
}

impl Default for OracleConfig {
fn default() -> Self {
Self::Pragma(PragmaOracle::default())
}
}

impl Default for HttpProviderConfig {
fn default() -> Self {
Self { rpc_endpoint: default_rpc_endpoint(), tx_poll_interval_ms: None, gas_price_poll_ms: None }
Expand Down
44 changes: 24 additions & 20 deletions crates/client/l1-gas-price/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use anyhow::{format_err, Result};
use ethers::types::U256;
use ethers::utils::__serde_json::json;
use futures::lock::Mutex;
use mc_eth_client::config::EthereumClientConfig;
use mc_eth_client::config::{EthereumClientConfig, OracleConfig};
use mp_starknet_inherent::L1GasPrices;
use serde::Deserialize;
use tokio::time::sleep;
Expand All @@ -27,7 +27,7 @@ pub async fn run_worker(config: Arc<EthereumClientConfig>, gas_price: Arc<Mutex<
let poll_time = config.provider.gas_price_poll_ms().unwrap_or(DEFAULT_GAS_PRICE_POLL_MS);

loop {
match update_gas_price(rpc_endpoint.clone(), &client, gas_price.clone()).await {
match update_gas_price(rpc_endpoint.clone(), &client, gas_price.clone(), config.oracle.clone()).await {
Ok(_) => log::trace!("Updated gas prices"),
Err(e) => log::error!("Failed to update gas prices: {:?}", e),
}
Expand Down Expand Up @@ -60,6 +60,7 @@ async fn update_gas_price(
rpc_endpoint: String,
client: &reqwest::Client,
gas_price: Arc<Mutex<L1GasPrices>>,
oracle: OracleConfig,
) -> Result<()> {
let fee_history: EthRpcResponse<FeeHistory> = client
.post(rpc_endpoint.clone())
Expand Down Expand Up @@ -96,37 +97,40 @@ async fn update_gas_price(
16,
)?;

// TODO: fetch this from the oracle
let url = "https://api.dev.pragma.build/node/v1/data/eth/strk?interval=1min&aggregation=median";
let api_key = "";
let response = reqwest::Client::new()
.get(oracle.get_fetch_url(String::from("eth"), String::from("strk")))
.header("x-api-key", oracle.get_api_key())
.send()
.await?;

let response = reqwest::Client::new().get(url).header("x-api-key", api_key).send().await?;
let res_json = response.json::<ApiResponse>().await;

let mut gas_price = gas_price.lock().await;

let (price, decimal) = match response.json::<ApiResponse>().await {
match res_json {
Ok(api_response) => {
log::trace!("Retrieved ETH/STRK price from Pragma API");
(api_response.price, api_response.decimals)
log::trace!("Retrieved ETH/STRK price from Oracle");
let eth_strk_price = u128::from_str_radix(api_response.price.trim_start_matches("0x"), 16)?;
let stark_gas =
((U256::from(eth_gas_price) * U256::from(eth_strk_price)) / 10u64.pow(api_response.decimals)).as_u128();
let stark_data_gas = ((U256::from(avg_blob_base_fee) * U256::from(eth_strk_price))
/ 10u64.pow(api_response.decimals))
.as_u128();
gas_price.strk_l1_gas_price = NonZeroU128::new(stark_gas)
.ok_or(format_err!("Failed to convert `strk_l1_gas_price` to NonZeroU128"))?;
gas_price.strk_l1_data_gas_price = NonZeroU128::new(stark_data_gas)
.ok_or(format_err!("Failed to convert `strk_l1_data_gas_price` to NonZeroU128"))?;
}
Err(e) => {
log::error!("Failed to retrieve ETH/STRK price: {:?}", e);
(String::from(""), 0)
}
};

let eth_strk_price = u128::from_str_radix(price.trim_start_matches("0x"), 16).expect("Invalid hex string");

let stark_gas = ((U256::from(eth_gas_price) * U256::from(eth_strk_price)) / 10u64.pow(decimal)).as_u128();
let stark_data_gas = ((U256::from(avg_blob_base_fee) * U256::from(eth_strk_price)) / 10u64.pow(decimal)).as_u128();

let mut gas_price = gas_price.lock().await;
gas_price.eth_l1_gas_price =
NonZeroU128::new(eth_gas_price).ok_or(format_err!("Failed to convert `eth_gas_price` to NonZeroU128"))?;
gas_price.eth_l1_data_gas_price = NonZeroU128::new(avg_blob_base_fee)
.ok_or(format_err!("Failed to convert `eth_l1_data_gas_price` to NonZeroU128"))?;
gas_price.strk_l1_gas_price =
NonZeroU128::new(stark_gas).ok_or(format_err!("Failed to convert `strk_l1_gas_price` to NonZeroU128"))?;
gas_price.strk_l1_data_gas_price = NonZeroU128::new(stark_data_gas)
.ok_or(format_err!("Failed to convert `strk_l1_data_gas_price` to NonZeroU128"))?;

gas_price.last_update_timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH)?.as_millis();
// explicitly dropping gas price here to avoid long waits when fetching the value
// on the inherent side which would increase block time
Expand Down
8 changes: 7 additions & 1 deletion examples/messaging/eth-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@
},
"contracts": {
"core_contract": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512"
},
"oracle": {
"api_url": "https://api.dev.pragma.build/node/v1/data/eth/strk?interval=1min&aggregation=median",
"api_key": "",
"aggregation_method": "median",
"interval": "1min"
}
}
}

0 comments on commit 081939b

Please sign in to comment.