Skip to content

Commit

Permalink
feat: add configurable priority fee multiplier
Browse files Browse the repository at this point in the history
Co-Authored-By: Jayant Krishnamurthy <[email protected]>
  • Loading branch information
devin-ai-integration[bot] and Jayant Krishnamurthy committed Dec 12, 2024
1 parent cc16040 commit 235a205
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 15 deletions.
67 changes: 58 additions & 9 deletions apps/fortuna/src/chain/eth_gas_oracle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,47 @@ pub const EIP1559_FEE_ESTIMATION_THRESHOLD_MAX_CHANGE: i64 = 200;
#[must_use]
pub struct EthProviderOracle<M: Middleware> {
provider: M,
priority_fee_multiplier_pct: u64,
}

impl<M: Middleware> EthProviderOracle<M> {
pub fn new(provider: M) -> Self {
Self { provider }
pub fn new(provider: M, priority_fee_multiplier_pct: u64) -> Self {
Self {
provider,
priority_fee_multiplier_pct,
}
}

/// The default EIP-1559 fee estimator which is based on the work by [MyCrypto](https://github.com/MyCryptoHQ/MyCrypto/blob/master/src/services/ApiService/Gas/eip1559.ts)
pub fn eip1559_default_estimator(
&self,
base_fee_per_gas: U256,
rewards: Vec<Vec<U256>>,
) -> (U256, U256) {
let max_priority_fee_per_gas =
if base_fee_per_gas < U256::from(EIP1559_FEE_ESTIMATION_PRIORITY_FEE_TRIGGER) {
U256::from(EIP1559_FEE_ESTIMATION_DEFAULT_PRIORITY_FEE)
} else {
std::cmp::max(
estimate_priority_fee(rewards),
U256::from(EIP1559_FEE_ESTIMATION_DEFAULT_PRIORITY_FEE),
)
};

// Apply the multiplier to max_priority_fee_per_gas
let max_priority_fee_per_gas = max_priority_fee_per_gas
.checked_mul(U256::from(self.priority_fee_multiplier_pct))
.unwrap_or(max_priority_fee_per_gas)
.checked_div(U256::from(100))
.unwrap_or(max_priority_fee_per_gas);

let potential_max_fee = base_fee_surged(base_fee_per_gas);
let max_fee_per_gas = if max_priority_fee_per_gas > potential_max_fee {
max_priority_fee_per_gas + potential_max_fee
} else {
potential_max_fee
};
(max_fee_per_gas, max_priority_fee_per_gas)
}
}

Expand All @@ -61,25 +97,38 @@ where
}

async fn estimate_eip1559_fees(&self) -> Result<(U256, U256)> {
self.provider
.estimate_eip1559_fees(Some(eip1559_default_estimator))
let (max_fee_per_gas, max_priority_fee_per_gas) = self
.provider
.estimate_eip1559_fees(Some(estimate_base_fees))
.await
.map_err(|err| GasOracleError::ProviderError(Box::new(err)))
.map_err(|err| GasOracleError::ProviderError(Box::new(err)))?;

// Apply the multiplier to max_priority_fee_per_gas
let max_priority_fee_per_gas = max_priority_fee_per_gas
.checked_mul(U256::from(self.priority_fee_multiplier_pct))
.unwrap_or(max_priority_fee_per_gas)
.checked_div(U256::from(100))
.unwrap_or(max_priority_fee_per_gas);

// Recalculate max_fee_per_gas with the new priority fee
let max_fee_per_gas = std::cmp::max(max_fee_per_gas, max_priority_fee_per_gas);

Ok((max_fee_per_gas, max_priority_fee_per_gas))
}
}

/// The default EIP-1559 fee estimator which is based on the work by [MyCrypto](https://github.com/MyCryptoHQ/MyCrypto/blob/master/src/services/ApiService/Gas/eip1559.ts)
pub fn eip1559_default_estimator(base_fee_per_gas: U256, rewards: Vec<Vec<U256>>) -> (U256, U256) {
fn estimate_base_fees(base_fee: U256, rewards: Vec<Vec<U256>>) -> (U256, U256) {
let max_priority_fee_per_gas =
if base_fee_per_gas < U256::from(EIP1559_FEE_ESTIMATION_PRIORITY_FEE_TRIGGER) {
if base_fee < U256::from(EIP1559_FEE_ESTIMATION_PRIORITY_FEE_TRIGGER) {
U256::from(EIP1559_FEE_ESTIMATION_DEFAULT_PRIORITY_FEE)
} else {
std::cmp::max(
estimate_priority_fee(rewards),
U256::from(EIP1559_FEE_ESTIMATION_DEFAULT_PRIORITY_FEE),
)
};
let potential_max_fee = base_fee_surged(base_fee_per_gas);

let potential_max_fee = base_fee_surged(base_fee);
let max_fee_per_gas = if max_priority_fee_per_gas > potential_max_fee {
max_priority_fee_per_gas + potential_max_fee
} else {
Expand Down
3 changes: 2 additions & 1 deletion apps/fortuna/src/chain/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ impl<T: JsonRpcClient + 'static + Clone> SignablePythContractInner<T> {
provider: Provider<T>,
) -> Result<SignablePythContractInner<T>> {
let chain_id = provider.get_chainid().await?;
let gas_oracle = EthProviderOracle::new(provider.clone());
let gas_oracle =
EthProviderOracle::new(provider.clone(), chain_config.priority_fee_multiplier_pct);
let wallet__ = private_key
.parse::<LocalWallet>()?
.with_chain_id(chain_id.as_u64());
Expand Down
8 changes: 8 additions & 0 deletions apps/fortuna/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ pub struct EthereumConfig {
/// Maximum number of hashes to record in a request.
/// This should be set according to the maximum gas limit the provider supports for callbacks.
pub max_num_hashes: Option<u32>,

/// The percentage multiplier to apply to the priority fee (100 = no change, e.g. 150 = 150% of base fee)
#[serde(default = "default_priority_fee_multiplier_pct")]
pub priority_fee_multiplier_pct: u64,
}

/// A commitment that the provider used to generate random numbers at some point in the past.
Expand Down Expand Up @@ -215,6 +219,10 @@ fn default_chain_sample_interval() -> u64 {
1
}

fn default_priority_fee_multiplier_pct() -> u64 {
100
}

/// Configuration values for the keeper service that are shared across chains.
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct KeeperConfig {
Expand Down
13 changes: 8 additions & 5 deletions apps/fortuna/src/keeper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
crate::{
api::{self, BlockchainState, ChainId},
chain::{
eth_gas_oracle::eip1559_default_estimator,
eth_gas_oracle::EthProviderOracle,
ethereum::{
InstrumentedPythContract, InstrumentedSignablePythContract, PythContractCall,
},
Expand All @@ -14,6 +14,7 @@ use {
anyhow::{anyhow, Result},
backoff::ExponentialBackoff,
ethers::{
prelude::GasOracle,
providers::{Middleware, Provider, Ws},
signers::Signer,
types::{Address, U256},
Expand Down Expand Up @@ -1208,11 +1209,13 @@ pub async fn estimate_tx_cost(
.try_into()
.map_err(|e| anyhow!("gas price doesn't fit into 128 bits. error: {:?}", e))?
} else {
let (max_fee_per_gas, max_priority_fee_per_gas) = middleware
.estimate_eip1559_fees(Some(eip1559_default_estimator))
.await?;
let gas_oracle = EthProviderOracle::new(middleware.clone(), 100);
let (max_fee_per_gas, _) = gas_oracle
.estimate_eip1559_fees()
.await
.map_err(|e| anyhow!("Failed to estimate gas price: {}", e))?;

(max_fee_per_gas + max_priority_fee_per_gas)
max_fee_per_gas
.try_into()
.map_err(|e| anyhow!("gas price doesn't fit into 128 bits. error: {:?}", e))?
};
Expand Down

0 comments on commit 235a205

Please sign in to comment.