Ver código fonte

feat: add configurable priority fee multiplier (#2195)

* feat: add configurable priority fee multiplier

Co-Authored-By: Jayant Krishnamurthy <jayant@dourolabs.xyz>

* hm

* fix this up a bit

* fix this up a bit

* fix this up a bit

* fix this up a bit

* chore: fix rust formatting

Co-Authored-By: Jayant Krishnamurthy <jayant@dourolabs.xyz>

* sample

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Jayant Krishnamurthy <jayant@dourolabs.xyz>
Co-authored-by: Jayant Krishnamurthy <jayantkrishnamurthy@gmail.com>
devin-ai-integration[bot] 11 meses atrás
pai
commit
a26f3354c6

+ 1 - 1
apps/fortuna/Cargo.lock

@@ -1503,7 +1503,7 @@ dependencies = [
 
 [[package]]
 name = "fortuna"
-version = "6.5.5"
+version = "6.6.0"
 dependencies = [
  "anyhow",
  "axum",

+ 1 - 1
apps/fortuna/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name    = "fortuna"
-version = "6.5.5"
+version = "6.6.0"
 edition = "2021"
 
 [dependencies]

+ 4 - 0
apps/fortuna/config.sample.yaml

@@ -12,6 +12,10 @@ chains:
     # How much to charge in fees
     fee: 1500000000000000
 
+    # Multiplier for the priority fee estimate, as a percentage (i.e., 100 = no change).
+    # Defaults to 100 if the field is omitted.
+    priority_fee_multiplier_pct: 100
+
     # Configuration for dynamic fees under high gas prices. The keeper will set
     # on-chain fees to make between [min_profit_pct, max_profit_pct] of the max callback
     # cost in profit per transaction.

+ 19 - 4
apps/fortuna/src/chain/eth_gas_oracle.rs

@@ -39,11 +39,15 @@ 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,
+        }
     }
 }
 
@@ -61,10 +65,19 @@ where
     }
 
     async fn estimate_eip1559_fees(&self) -> Result<(U256, U256)> {
-        self.provider
+        let (max_fee_per_gas, max_priority_fee_per_gas) = self
+            .provider
             .estimate_eip1559_fees(Some(eip1559_default_estimator))
             .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))
+            .and_then(|x| x.checked_div(U256::from(100)))
+            .unwrap_or(max_priority_fee_per_gas);
+
+        Ok((max_fee_per_gas, max_priority_fee_per_gas))
     }
 }
 
@@ -79,12 +92,14 @@ pub fn eip1559_default_estimator(base_fee_per_gas: U256, rewards: Vec<Vec<U256>>
                 U256::from(EIP1559_FEE_ESTIMATION_DEFAULT_PRIORITY_FEE),
             )
         };
+
     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)
 }
 

+ 2 - 1
apps/fortuna/src/chain/ethereum.rs

@@ -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());

+ 8 - 0
apps/fortuna/src/config.rs

@@ -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.
@@ -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 {

+ 5 - 4
apps/fortuna/src/keeper.rs

@@ -2,7 +2,6 @@ use {
     crate::{
         api::{self, BlockchainState, ChainId},
         chain::{
-            eth_gas_oracle::eip1559_default_estimator,
             ethereum::{
                 InstrumentedPythContract, InstrumentedSignablePythContract, PythContractCall,
             },
@@ -1208,9 +1207,11 @@ 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?;
+        // This is not obvious but the implementation of estimate_eip1559_fees in ethers.rs
+        // for a middleware that has a GasOracleMiddleware inside is to ignore the passed-in callback
+        // and use whatever the gas oracle returns.
+        let (max_fee_per_gas, max_priority_fee_per_gas) =
+            middleware.estimate_eip1559_fees(None).await?;
 
         (max_fee_per_gas + max_priority_fee_per_gas)
             .try_into()