Skip to content

Commit

Permalink
new test for closing trades after maturity (#196)
Browse files Browse the repository at this point in the history
# Resolved Issues
#197

# Description
This PR adds a test to ensure that the `calculate_close_long` and
`calculate_close_short` function correctly handle proceeds going to LPs
after maturity.
  • Loading branch information
dpaiton authored Oct 2, 2024
1 parent 9906b0d commit 5dca80f
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 2 deletions.
42 changes: 40 additions & 2 deletions crates/hyperdrive-math/src/long/close.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,53 @@ mod tests {
use super::*;

#[tokio::test]
async fn fuzz_calculate_close_long_flat_plus_curve() -> Result<()> {
async fn fuzz_calculate_close_long_after_maturity() -> Result<()> {
// TODO: This simulates a 0% variable rate because the vault share price
// does not change over time. We should write one with a positive rate.
let mut rng = thread_rng();
for _ in 0..*FAST_FUZZ_RUNS {
let state = rng.gen::<State>();
let in_ = rng.gen_range(fixed!(0)..=state.effective_share_reserves()?);
// NOTE: The actual maturity time could be shy of position_duration
// if the checkpoint_duration does not evenly divide into
// position_duration.
let maturity_time = state.position_duration();
// Close a long just after it has matured.
let just_after_maturity = maturity_time + state.checkpoint_duration();
let base_earned_just_after_maturity = state.calculate_close_long(
in_,
maturity_time.into(),
just_after_maturity.into(),
)? * state.vault_share_price();
// Close a long a good while after it has matured.
let well_after_maturity = just_after_maturity + fixed!(1e10);
let base_earned_well_after_maturity = state.calculate_close_long(
in_,
maturity_time.into(),
well_after_maturity.into(),
)? * state.vault_share_price();
// Check that no extra money was earned.
assert!(
base_earned_well_after_maturity == base_earned_just_after_maturity,
"Trader should not have earned any more after maturity:
earned_well_after_maturity={:?} != earned_just_after_maturity={:?}",
base_earned_well_after_maturity,
base_earned_just_after_maturity
);
}
Ok(())
}

#[tokio::test]
async fn fuzz_sol_calculate_close_long_flat_plus_curve() -> Result<()> {
let chain = TestChain::new().await?;

// Fuzz the rust and solidity implementations against each other.
let mut rng = thread_rng();
for _ in 0..*FAST_FUZZ_RUNS {
let state = rng.gen::<State>();
let in_ = rng.gen_range(fixed!(0)..=state.effective_share_reserves()?);
let maturity_time = state.checkpoint_duration();
let maturity_time = state.position_duration();
let current_time = rng.gen_range(fixed!(0)..=maturity_time);
let normalized_time_remaining = state
.calculate_normalized_time_remaining(maturity_time.into(), current_time.into());
Expand Down
43 changes: 43 additions & 0 deletions crates/hyperdrive-math/src/short/close.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,49 @@ mod tests {

use super::*;

#[tokio::test]
async fn fuzz_calculate_close_short_after_maturity() -> Result<()> {
// TODO: This simulates a 0% variable rate because the vault share price
// does not change over time. We should write one with a positive rate.
let mut rng = thread_rng();
for _ in 0..*FAST_FUZZ_RUNS {
let state = rng.gen::<State>();
let in_ = rng.gen_range(fixed!(0)..=state.effective_share_reserves()?);
let open_vault_share_price = rng.gen_range(fixed!(0)..=state.vault_share_price());
// NOTE: The actual maturity time could be shy of position_duration
// if the checkpoint_duration does not evenly divide into
// position_duration.
let maturity_time = state.position_duration();
// Close a short just after it has matured.
let just_after_maturity = maturity_time + state.checkpoint_duration();
let base_earned_just_after_maturity = state.calculate_close_short(
in_,
open_vault_share_price,
state.vault_share_price(),
maturity_time.into(),
just_after_maturity.into(),
)? * state.vault_share_price();
// Close a short a good while after it has matured.
let well_after_maturity = just_after_maturity + fixed!(1e10);
let base_earned_well_after_maturity = state.calculate_close_short(
in_,
open_vault_share_price,
state.vault_share_price(),
maturity_time.into(),
well_after_maturity.into(),
)? * state.vault_share_price();
// Check that no extra money was earned.
assert!(
base_earned_well_after_maturity == base_earned_just_after_maturity,
"Trader should not have earned any more after maturity:
earned_well_after_maturity={:?} != earned_just_after_maturity={:?}",
base_earned_well_after_maturity,
base_earned_just_after_maturity
);
}
Ok(())
}

#[tokio::test]
async fn fuzz_sol_calculate_short_proceeds_up() -> Result<()> {
let chain = TestChain::new().await?;
Expand Down

0 comments on commit 5dca80f

Please sign in to comment.