This repository has been archived by the owner on Aug 21, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 108
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Objects and methods for STRK gas price calculation (#928)
* Added objects and methods to compute gas price in STRK. * fix clippy error.
- Loading branch information
1 parent
bfa8c3a
commit 19e54f7
Showing
5 changed files
with
168 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
pub mod errors; | ||
pub mod eth_gas_constants; | ||
pub mod fee_utils; | ||
pub mod gas_usage; | ||
pub mod os_resources; | ||
pub mod os_usage; | ||
pub mod strk_gas_price; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
use thiserror::Error; | ||
|
||
#[derive(Debug, Error)] | ||
pub enum StrkGasPriceCalcError { | ||
#[error("No pool states provided.")] | ||
NoPoolStatesError, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
use std::cmp::Ordering; | ||
|
||
use num_bigint::BigUint; | ||
use num_traits::Zero; | ||
|
||
use super::errors::StrkGasPriceCalcError; | ||
|
||
#[cfg(test)] | ||
#[path = "strk_gas_price_test.rs"] | ||
pub mod test; | ||
|
||
/// Struct representing the current state of a STRK<->ETH AMM pool. | ||
#[derive(Clone, Debug)] | ||
pub struct PoolState { | ||
pub total_wei: BigUint, | ||
pub total_strk: BigUint, | ||
} | ||
|
||
impl PoolState { | ||
pub fn tvl_in_wei(&self) -> BigUint { | ||
// Assumption on pool is the two pools have the same total value. | ||
self.total_wei.clone() << 1 | ||
} | ||
/// Returns the result of comparing two pool states by STRK / Wei ratio. | ||
pub fn compare_strk_to_wei_ratio(&self, other: &Self) -> Ordering { | ||
// a / b < c / d <=> a * d < c * b. The same is true for the other orders. | ||
let lhs = self.total_strk.clone() * other.total_wei.clone(); | ||
let rhs = other.total_strk.clone() * self.total_wei.clone(); | ||
lhs.cmp(&rhs) | ||
} | ||
} | ||
|
||
/// Struct representing aggregate of STRK<->ETH AMM pools. | ||
/// Converts Wei to STRK at the STRK / Wei ratio of the weighted median pool state. | ||
#[derive(Clone, Debug)] | ||
pub struct PoolStateAggregator { | ||
// Pool states are sorted by STRK / Wei ratio. | ||
pub sorted_pool_states: Vec<PoolState>, | ||
// See PoolStateAggregator::calc_median_values() for more info on median calculation. | ||
pub median_pool_strk_tvl: BigUint, | ||
pub median_pool_wei_tvl: BigUint, | ||
} | ||
|
||
impl PoolStateAggregator { | ||
pub fn new(pool_states: &[PoolState]) -> Result<Self, StrkGasPriceCalcError> { | ||
if pool_states.is_empty() { | ||
return Err(StrkGasPriceCalcError::NoPoolStatesError); | ||
} | ||
|
||
let mut sorted_pool_states: Vec<PoolState> = pool_states.to_vec(); | ||
sorted_pool_states.sort_unstable_by(|pool_state_a, pool_state_b| { | ||
pool_state_a.compare_strk_to_wei_ratio(pool_state_b) | ||
}); | ||
|
||
let (median_pool_strk_tvl, median_pool_wei_tvl) = | ||
Self::calc_median_values(&sorted_pool_states); | ||
|
||
Ok(Self { sorted_pool_states, median_pool_strk_tvl, median_pool_wei_tvl }) | ||
} | ||
|
||
/// Returns the STRK and Wei TVL of the weighted median pool state: | ||
/// The pool state with a STRK TVL / Wei TVL ratio such that the sum of the weights of the pool | ||
/// states with a smaller ratio is smaller or equal to half the total weight (and the same for | ||
/// pools with a larger ratio). If two such pools exist the average is returned. | ||
/// The pool states are weighted by the total TVL in Wei. | ||
/// This function assumes the given slice is sorted by STRK / Wei ratio. | ||
pub fn calc_median_values(sorted_pool_states: &[PoolState]) -> (BigUint, BigUint) { | ||
let total_weight: BigUint = | ||
sorted_pool_states.iter().map(|state| state.tvl_in_wei()).sum::<BigUint>(); | ||
|
||
// Find index of weighted median STRK / Wei ratio. | ||
let mut current_weight: BigUint = BigUint::zero(); | ||
let mut median_idx = 0; | ||
let equal_weight_partition: bool; | ||
loop { | ||
current_weight += sorted_pool_states[median_idx].tvl_in_wei().clone(); | ||
if current_weight.clone() << 1 >= total_weight { | ||
equal_weight_partition = current_weight << 1 == total_weight; | ||
break; | ||
} | ||
median_idx += 1; | ||
} | ||
|
||
let median_pool_strk_tvl: BigUint; | ||
let median_pool_wei_tvl: BigUint; | ||
if equal_weight_partition { | ||
median_pool_strk_tvl = (sorted_pool_states[median_idx].total_strk.clone() | ||
+ sorted_pool_states[median_idx + 1].total_strk.clone()) | ||
/ BigUint::from(2_u32); | ||
median_pool_wei_tvl = (sorted_pool_states[median_idx].total_wei.clone() | ||
+ sorted_pool_states[median_idx + 1].total_wei.clone()) | ||
/ BigUint::from(2_u32); | ||
} else { | ||
median_pool_strk_tvl = sorted_pool_states[median_idx].total_strk.clone(); | ||
median_pool_wei_tvl = sorted_pool_states[median_idx].total_wei.clone(); | ||
} | ||
(median_pool_strk_tvl, median_pool_wei_tvl) | ||
} | ||
|
||
pub fn convert_wei_to_strk(&self, wei_amount: BigUint) -> BigUint { | ||
(wei_amount * self.median_pool_strk_tvl.clone()) / self.median_pool_wei_tvl.clone() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
use num_bigint::BigUint; | ||
|
||
use crate::fee::errors::StrkGasPriceCalcError; | ||
use crate::fee::strk_gas_price::{PoolState, PoolStateAggregator}; | ||
|
||
/// Sanity tests for STRK<->ETH price computation. | ||
#[test] | ||
fn test_convert_wei_to_strk() { | ||
let (wei_1, wei_2, wei_3) = | ||
(BigUint::from(10_u32), BigUint::from(14_u32), BigUint::from(12_u32)); | ||
let (strk_1, strk_2, strk_3, strk_4) = ( | ||
BigUint::from(50_u32), | ||
BigUint::from(42_u32), | ||
BigUint::from(24_u32), | ||
BigUint::from(150_u32), | ||
); | ||
let state_1 = PoolState { total_wei: wei_1.clone(), total_strk: strk_1 }; | ||
let state_2 = PoolState { total_wei: wei_2, total_strk: strk_2 }; | ||
let state_3 = PoolState { total_wei: wei_3, total_strk: strk_3 }; | ||
let state_4 = PoolState { total_wei: wei_1, total_strk: strk_4 }; | ||
let wei_amount = BigUint::from(10_000_000_000_u64); | ||
|
||
// Bad flow: ratio computation on empty array. | ||
assert!(matches!(PoolStateAggregator::new(&[]), Err(StrkGasPriceCalcError::NoPoolStatesError))); | ||
|
||
// Convert Wei -> STRK with a single pool state. | ||
assert_eq!( | ||
PoolStateAggregator::new(&[state_1.clone()]) | ||
.unwrap() | ||
.convert_wei_to_strk(wei_amount.clone()), | ||
(state_1.total_strk.clone() * wei_amount.clone()) / state_1.total_wei.clone() | ||
); | ||
|
||
// Convert Wei -> STRK with multiple pool states, no equal weight partition. | ||
assert_eq!( | ||
PoolStateAggregator::new(&[state_3.clone(), state_1.clone()]) | ||
.unwrap() | ||
.convert_wei_to_strk(wei_amount.clone()), | ||
(state_3.total_strk.clone() * wei_amount.clone()) / state_3.total_wei.clone() | ||
); | ||
assert_eq!( | ||
PoolStateAggregator::new(&[state_3, state_1.clone(), state_2.clone()]) | ||
.unwrap() | ||
.convert_wei_to_strk(wei_amount.clone()), | ||
(state_2.total_strk.clone() * wei_amount.clone()) / state_2.total_wei.clone() | ||
); | ||
|
||
// Convert Wei -> STRK with multiple pool states with equal weight partition. | ||
assert_eq!( | ||
PoolStateAggregator::new(&[state_1.clone(), state_4.clone()]) | ||
.unwrap() | ||
.convert_wei_to_strk(wei_amount.clone()), | ||
((state_1.total_strk + state_4.total_strk) * wei_amount) | ||
/ (state_1.total_wei + state_4.total_wei) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters