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

Commit

Permalink
feat: add constructors to gas escalators
Browse files Browse the repository at this point in the history
  • Loading branch information
gakonst committed Oct 7, 2020
1 parent 2fc8c1b commit 23a6fa8
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 51 deletions.
39 changes: 18 additions & 21 deletions ethers-middleware/src/gas_escalator/geometric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<U256>,
}

impl Default for GeometricGasPrice {
fn default() -> Self {
Self::new()
}
every_secs: u64,
coefficient: f64,
max_price: Option<U256>,
}

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::<u64>)`.
pub fn new<T: Into<U256>, K: Into<u64>>(
coefficient: f64,
every_secs: K,
max_price: Option<T>,
) -> Self {
GeometricGasPrice {
every_secs: 30,
coefficient: 1.125,
max_price: None,
every_secs: every_secs.into(),
coefficient,
max_price: max_price.map(Into::into),
}
}
}
Expand Down Expand Up @@ -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::<u64>);
let initial_price = U256::from(100);

assert_eq!(oracle.get_gas_price(initial_price, 0), 100.into());
Expand All @@ -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());
Expand All @@ -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::<u64>);
const GWEI: f64 = 1000000000.0;
let initial_price = U256::from(100 * GWEI as u64);

Expand Down
35 changes: 15 additions & 20 deletions ethers-middleware/src/gas_escalator/linear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,34 @@ 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<U256>,
}

impl Default for LinearGasPrice {
fn default() -> Self {
Self::new()
}
every_secs: u64,
increase_by: U256,
max_price: Option<U256>,
}

impl LinearGasPrice {
/// Constructor
pub fn new() -> Self {
pub fn new<T: Into<U256>>(
increase_by: T,
every_secs: impl Into<u64>,
max_price: Option<T>,
) -> 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),
}
}
}

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);
}
Expand All @@ -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());
Expand All @@ -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());
Expand Down
4 changes: 1 addition & 3 deletions ethers-middleware/src/gas_escalator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u64>);
/// GasEscalatorMiddleware::new(provider, escalator, Frequency::PerBlock)
/// };
///
Expand Down
3 changes: 2 additions & 1 deletion ethers-middleware/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
//! let provider = Provider::<Http>::try_from("http://localhost:8545").unwrap();
//!
//! // Escalate gas prices
//! let escalator = GeometricGasPrice::new(1.125, 60u64, None::<u64>);
//! 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());
Expand Down
5 changes: 1 addition & 4 deletions ethers-middleware/tests/gas_escalator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down
4 changes: 2 additions & 2 deletions ethers-middleware/tests/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u64>);
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);
Expand Down

0 comments on commit 23a6fa8

Please sign in to comment.