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

dev : add pragma api to compute fees in STRK #1633

Merged
merged 19 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
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 {
EvolveArt marked this conversation as resolved.
Show resolved Hide resolved
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)]
EvolveArt marked this conversation as resolved.
Show resolved Hide resolved
pub enum AggregationMethod {
#[serde(rename = "median")]
#[default]
EvolveArt marked this conversation as resolved.
Show resolved Hide resolved
Median,
#[serde(rename = "mean")]
Mean,
#[serde(rename = "twap")]
Twap,
}

// impl fmt::Display for AggregationMethod {
EvolveArt marked this conversation as resolved.
Show resolved Hide resolved
// 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)]
EvolveArt marked this conversation as resolved.
Show resolved Hide resolved
pub enum Interval {
#[serde(rename = "1min")]
#[default]
EvolveArt marked this conversation as resolved.
Show resolved Hide resolved
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 {
EvolveArt marked this conversation as resolved.
Show resolved Hide resolved
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(""),
EvolveArt marked this conversation as resolved.
Show resolved Hide resolved
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
47 changes: 39 additions & 8 deletions crates/client/l1-gas-price/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,31 @@ use std::sync::Arc;
use std::time::Duration;

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;

use crate::types::{EthRpcResponse, FeeHistory};

const DEFAULT_GAS_PRICE_POLL_MS: u64 = 10_000;

#[derive(Deserialize, Debug)]
struct ApiResponse {
price: String,
decimals: u32,
}

pub async fn run_worker(config: Arc<EthereumClientConfig>, gas_price: Arc<Mutex<L1GasPrices>>, infinite_loop: bool) {
let rpc_endpoint = config.provider.rpc_endpoint().clone();
let client = reqwest::Client::new();
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 @@ -52,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 @@ -88,18 +97,40 @@ async fn update_gas_price(
16,
)?;

// TODO: fetch this from the oracle
let eth_strk_price = 2425;
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?;
tdelabro marked this conversation as resolved.
Show resolved Hide resolved

let res_json = response.json::<ApiResponse>().await;

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

match res_json {
EvolveArt marked this conversation as resolved.
Show resolved Hide resolved
Ok(api_response) => {
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);
}
};

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(eth_gas_price.saturating_mul(eth_strk_price))
.ok_or(format_err!("Failed to convert `strk_l1_gas_price` to NonZeroU128"))?;
gas_price.strk_l1_data_gas_price = NonZeroU128::new(avg_blob_base_fee.saturating_mul(eth_strk_price))
.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",
EvolveArt marked this conversation as resolved.
Show resolved Hide resolved
"api_key": "",
"aggregation_method": "median",
"interval": "1min"
EvolveArt marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Loading