Skip to content

Commit

Permalink
time stretch bugfix (#727)
Browse files Browse the repository at this point in the history
  • Loading branch information
dpaiton authored Jan 18, 2024
1 parent 10691c2 commit 570263e
Showing 1 changed file with 18 additions and 17 deletions.
35 changes: 18 additions & 17 deletions crates/hyperdrive-math/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ use ethers::types::{I256, U256};
use fixed_point::FixedPoint;
use fixed_point_macros::{fixed, uint256};

pub fn get_time_stretch(mut rate: FixedPoint, position_duration: FixedPoint) -> FixedPoint {
pub fn get_time_stretch(rate: FixedPoint, position_duration: FixedPoint) -> FixedPoint {
let seconds_in_a_year = FixedPoint::from(U256::from(60 * 60 * 24 * 365));
let annualized_time = position_duration / seconds_in_a_year;
rate = (U256::from(rate) * uint256!(100)).into();
// Calculate the benchmark time stretch. This time stretch is tuned for
// a position duration of 1 year.
let time_stretch = fixed!(1e18) / (fixed!(5.24592e18) / (fixed!(0.04665e18) * rate));
let time_stretch = fixed!(5.24592e18)
/ (fixed!(0.04665e18) * FixedPoint::from(U256::from(rate) * uint256!(100)));
let time_stretch = fixed!(1e18) / time_stretch;
// if the position duration is 1 year, we can return the benchmark
if annualized_time == fixed!(1e18) {
if position_duration == seconds_in_a_year {
return time_stretch;
}

Expand All @@ -33,6 +33,8 @@ pub fn get_time_stretch(mut rate: FixedPoint, position_duration: FixedPoint) ->
// p = ratio ** timeStretch
// =>
// timeStretch = ln(p) / ln(ratio)
let target_spot_price =
fixed!(1e18) / (fixed!(1e18) + rate.mul_div_down(position_duration, seconds_in_a_year));
let benchmark_reserve_ratio = fixed!(1e18)
/ calculate_initial_bond_reserves(
fixed!(1e18),
Expand All @@ -41,16 +43,12 @@ pub fn get_time_stretch(mut rate: FixedPoint, position_duration: FixedPoint) ->
seconds_in_a_year,
time_stretch,
);
let target_spot_price = fixed!(1e18) / (fixed!(1e18) * annualized_time);
// target spot price and benchmark reserve ratio will have negative ln,
// but since we are dividing them we can cast to positive before converting types
// TODO: implement FixedPoint `neg` pub fn to support "-"
let new_time_stretch = U256::from(FixedPoint::from(-FixedPoint::ln(I256::from(
target_spot_price,
)))) / U256::from(FixedPoint::from(-FixedPoint::ln(I256::from(
benchmark_reserve_ratio,
))));
new_time_stretch.into()
let new_time_stretch = FixedPoint::from(-FixedPoint::ln(I256::from(target_spot_price)))
/ FixedPoint::from(-FixedPoint::ln(I256::from(benchmark_reserve_ratio)));
new_time_stretch
}

pub fn get_effective_share_reserves(
Expand Down Expand Up @@ -117,15 +115,18 @@ mod tests {
let chain = TestChainWithMocks::new(1).await?;
let mock = chain.mock_hyperdrive_math();
// Fuzz the rust and solidity implementations against each other.
let apr = fixed!(0.05e18); // 5%
let seconds_in_a_year = U256::from(60 * 60 * 24 * 365);
let seconds_in_ten_years = U256::from(10 * 60 * 60 * 24 * 365);
let seconds_in_a_day = U256::from(60 * 60 * 24);
let mut rng = thread_rng();
for _ in 0..*FAST_FUZZ_RUNS {
// Get the current state of the mock contract
let state = rng.gen::<State>();
let actual_t = get_time_stretch(apr, seconds_in_a_year.into());
let position_duration = rng.gen_range(
FixedPoint::from(seconds_in_a_day)..=FixedPoint::from(seconds_in_ten_years),
);
let apr = rng.gen_range(fixed!(0.001e18)..=fixed!(10.0e18));
let actual_t = get_time_stretch(apr, position_duration);
match mock
.calculate_time_stretch(apr.into(), seconds_in_a_year)
.calculate_time_stretch(apr.into(), position_duration.into())
.call()
.await
{
Expand Down

0 comments on commit 570263e

Please sign in to comment.