From 23a6fa8e9d7bf2193bd10e0cb5b1cb5e6280adff Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Wed, 7 Oct 2020 10:54:10 +0300 Subject: [PATCH] feat: add constructors to gas escalators --- .../src/gas_escalator/geometric.rs | 39 +++++++++---------- ethers-middleware/src/gas_escalator/linear.rs | 35 +++++++---------- ethers-middleware/src/gas_escalator/mod.rs | 4 +- ethers-middleware/src/lib.rs | 3 +- ethers-middleware/tests/gas_escalator.rs | 5 +-- ethers-middleware/tests/stack.rs | 4 +- 6 files changed, 39 insertions(+), 51 deletions(-) diff --git a/ethers-middleware/src/gas_escalator/geometric.rs b/ethers-middleware/src/gas_escalator/geometric.rs index 98f08584c..dcbba6c73 100644 --- a/ethers-middleware/src/gas_escalator/geometric.rs +++ b/ethers-middleware/src/gas_escalator/geometric.rs @@ -6,27 +6,29 @@ use ethers_core::types::U256; /// Start with `initial_price`, then increase it every 'every_secs' seconds by a fixed coefficient. /// Coefficient defaults to 1.125 (12.5%), the minimum increase for Parity to replace a transaction. /// Coefficient can be adjusted, and there is an optional upper limit. +/// /// https://github.com/makerdao/pymaker/blob/master/pymaker/gas.py#L168 #[derive(Clone, Debug)] pub struct GeometricGasPrice { - pub every_secs: u64, - pub coefficient: f64, - pub max_price: Option, -} - -impl Default for GeometricGasPrice { - fn default() -> Self { - Self::new() - } + every_secs: u64, + coefficient: f64, + max_price: Option, } impl GeometricGasPrice { /// Constructor - pub fn new() -> Self { + /// + /// Note: Providing `None` to `max_price` requires giving it a type-hint, so you'll need + /// to call this like `GeometricGasPrice::new(1.125, 60u64, None::)`. + pub fn new, K: Into>( + coefficient: f64, + every_secs: K, + max_price: Option, + ) -> Self { GeometricGasPrice { - every_secs: 30, - coefficient: 1.125, - max_price: None, + every_secs: every_secs.into(), + coefficient, + max_price: max_price.map(Into::into), } } } @@ -57,8 +59,7 @@ mod tests { #[test] fn gas_price_increases_with_time() { - let mut oracle = GeometricGasPrice::new(); - oracle.every_secs = 10; + let oracle = GeometricGasPrice::new(1.125, 10u64, None::); let initial_price = U256::from(100); assert_eq!(oracle.get_gas_price(initial_price, 0), 100.into()); @@ -73,9 +74,7 @@ mod tests { #[test] fn gas_price_should_obey_max_value() { - let mut oracle = GeometricGasPrice::new(); - oracle.every_secs = 60; - oracle.max_price = Some(2500.into()); + let oracle = GeometricGasPrice::new(1.125, 60u64, Some(2500)); let initial_price = U256::from(1000); assert_eq!(oracle.get_gas_price(initial_price, 0), 1000.into()); @@ -91,9 +90,7 @@ mod tests { #[test] fn behaves_with_realistic_values() { - let mut oracle = GeometricGasPrice::new(); - oracle.every_secs = 10; - oracle.coefficient = 1.25; + let oracle = GeometricGasPrice::new(1.25, 10u64, None::); const GWEI: f64 = 1000000000.0; let initial_price = U256::from(100 * GWEI as u64); diff --git a/ethers-middleware/src/gas_escalator/linear.rs b/ethers-middleware/src/gas_escalator/linear.rs index d0904ccdc..e47b5bbd8 100644 --- a/ethers-middleware/src/gas_escalator/linear.rs +++ b/ethers-middleware/src/gas_escalator/linear.rs @@ -6,27 +6,26 @@ use ethers_core::types::U256; /// /// Start with `initial_price`, then increase it by fixed amount `increase_by` every `every_secs` seconds /// until the transaction gets confirmed. There is an optional upper limit. +/// /// https://github.com/makerdao/pymaker/blob/master/pymaker/gas.py#L129 #[derive(Clone, Debug)] pub struct LinearGasPrice { - pub every_secs: u64, - pub increase_by: U256, - pub max_price: Option, -} - -impl Default for LinearGasPrice { - fn default() -> Self { - Self::new() - } + every_secs: u64, + increase_by: U256, + max_price: Option, } impl LinearGasPrice { /// Constructor - pub fn new() -> Self { + pub fn new>( + increase_by: T, + every_secs: impl Into, + max_price: Option, + ) -> Self { LinearGasPrice { - every_secs: 30, - increase_by: U256::from(0), - max_price: None, + every_secs: every_secs.into(), + increase_by: increase_by.into(), + max_price: max_price.map(Into::into), } } } @@ -34,6 +33,7 @@ impl LinearGasPrice { impl GasEscalator for LinearGasPrice { fn get_gas_price(&self, initial_price: U256, time_elapsed: u64) -> U256 { let mut result = initial_price + self.increase_by * (time_elapsed / self.every_secs) as u64; + dbg!(time_elapsed, self.every_secs); if let Some(max_price) = self.max_price { result = std::cmp::min(result, max_price); } @@ -48,9 +48,7 @@ mod tests { #[test] fn gas_price_increases_with_time() { - let mut oracle = LinearGasPrice::new(); - oracle.increase_by = U256::from(100); - oracle.every_secs = 60; + let oracle = LinearGasPrice::new(100, 60u64, None); let initial_price = U256::from(1000); assert_eq!(oracle.get_gas_price(initial_price, 0), 1000.into()); @@ -64,10 +62,7 @@ mod tests { #[test] fn gas_price_should_obey_max_value() { - let mut oracle = LinearGasPrice::new(); - oracle.increase_by = U256::from(100); - oracle.every_secs = 60; - oracle.max_price = Some(2500.into()); + let oracle = LinearGasPrice::new(100, 60u64, Some(2500)); let initial_price = U256::from(1000); assert_eq!(oracle.get_gas_price(initial_price, 0), 1000.into()); diff --git a/ethers-middleware/src/gas_escalator/mod.rs b/ethers-middleware/src/gas_escalator/mod.rs index 5c40d36e5..991c3cb74 100644 --- a/ethers-middleware/src/gas_escalator/mod.rs +++ b/ethers-middleware/src/gas_escalator/mod.rs @@ -62,9 +62,7 @@ pub enum Frequency { /// .interval(Duration::from_millis(2000u64)); /// /// let provider = { -/// let mut escalator = GeometricGasPrice::new(); -/// escalator.every_secs = 10; -/// escalator.coefficient = 5.0; +/// let escalator = GeometricGasPrice::new(5.0, 10u64, None::); /// GasEscalatorMiddleware::new(provider, escalator, Frequency::PerBlock) /// }; /// diff --git a/ethers-middleware/src/lib.rs b/ethers-middleware/src/lib.rs index 3efe0c2ce..f976c199d 100644 --- a/ethers-middleware/src/lib.rs +++ b/ethers-middleware/src/lib.rs @@ -30,8 +30,9 @@ //! let provider = Provider::::try_from("http://localhost:8545").unwrap(); //! //! // Escalate gas prices +//! let escalator = GeometricGasPrice::new(1.125, 60u64, None::); //! let provider = -//! GasEscalatorMiddleware::new(provider, GeometricGasPrice::new(), Frequency::PerBlock); +//! GasEscalatorMiddleware::new(provider, escalator, Frequency::PerBlock); //! //! // Sign transactions with a private key //! let signer = LocalWallet::new(&mut rand::thread_rng()); diff --git a/ethers-middleware/tests/gas_escalator.rs b/ethers-middleware/tests/gas_escalator.rs index 98660f1f3..d4750cfe0 100644 --- a/ethers-middleware/tests/gas_escalator.rs +++ b/ethers-middleware/tests/gas_escalator.rs @@ -21,10 +21,7 @@ async fn gas_escalator_live() { let address = wallet.address(); let provider = SignerMiddleware::new(provider, wallet); - let mut escalator = GeometricGasPrice::new(); - escalator.every_secs = 10; - escalator.coefficient = 5.0; - escalator.max_price = Some(2000_000_000_000u64.into()); + let escalator = GeometricGasPrice::new(5.0, 10u64, Some(2000_000_000_000u64)); let provider = GasEscalatorMiddleware::new(provider, escalator, Frequency::Duration(3000)); diff --git a/ethers-middleware/tests/stack.rs b/ethers-middleware/tests/stack.rs index 01f98e31a..915e42ce5 100644 --- a/ethers-middleware/tests/stack.rs +++ b/ethers-middleware/tests/stack.rs @@ -24,8 +24,8 @@ async fn can_stack_middlewares() { // the Gas Price escalator middleware is the first middleware above the provider, // so that it receives the transaction last, after all the other middleware // have modified it accordingly - let provider = - GasEscalatorMiddleware::new(provider, GeometricGasPrice::new(), Frequency::PerBlock); + let escalator = GeometricGasPrice::new(1.125, 60u64, None::); + let provider = GasEscalatorMiddleware::new(provider, escalator, Frequency::PerBlock); // The gas price middleware MUST be below the signing middleware for things to work let provider = GasOracleMiddleware::new(provider, gas_oracle);