From af57bd3a705ae16167224fd30066eb60f37d81df Mon Sep 17 00:00:00 2001 From: Mihai Date: Wed, 1 May 2024 17:02:42 -0400 Subject: [PATCH 01/20] separate subtractions from share reserves to avoid negative value --- crates/hyperdrive-math/src/short/max.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index fbfd58e5..b3ce4047 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -437,10 +437,12 @@ impl State { }; let curve_fee_base = self.open_short_curve_fee(bond_amount)?; let share_reserves = self.share_reserves() - - (principal - - (curve_fee_base - - self.open_short_governance_fee(bond_amount, Some(curve_fee_base))?) - / self.vault_share_price()); + - principal + + ( + curve_fee_base + - self.open_short_governance_fee(bond_amount, Some(curve_fee_base))? + ) + / self.vault_share_price(); let exposure = { let checkpoint_exposure: FixedPoint = checkpoint_exposure.max(I256::zero()).try_into()?; From 222aeba7ee0b5491c593518a55595dcd8ca3e96d Mon Sep 17 00:00:00 2001 From: Mihai Date: Thu, 2 May 2024 12:35:24 -0400 Subject: [PATCH 02/20] fuzz over fixed rate --- crates/hyperdrive-math/src/short/max.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index b3ce4047..eb85a46e 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -608,10 +608,8 @@ mod tests { // Snapshot the chain. let id = chain.snapshot().await?; - // TODO: We should fuzz over a range of fixed rates. - // // Fund Alice and Bob. - let fixed_rate = fixed!(0.05e18); + let fixed_rate = rng.gen_range(fixed!(0.01e18)..=fixed!(0.1e18)); let contribution = rng.gen_range(fixed!(100_000e18)..=fixed!(100_000_000e18)); alice.fund(contribution).await?; From b9e3068bd5727202fa645973156a7c2ad86ef34a Mon Sep 17 00:00:00 2001 From: Mihai Date: Thu, 2 May 2024 12:37:47 -0400 Subject: [PATCH 03/20] fuzz 10x wider --- crates/hyperdrive-math/src/short/max.rs | 3 ++- crates/hyperdrive-test-utils/src/chain/deploy.rs | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index eb85a46e..55a18736 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -609,7 +609,8 @@ mod tests { let id = chain.snapshot().await?; // Fund Alice and Bob. - let fixed_rate = rng.gen_range(fixed!(0.01e18)..=fixed!(0.1e18)); + let fixed_rate = rng.gen_range(fixed!(0.01e18)..=fixed!(1e18)); + println!("Fixed rate: {}", fixed_rate); let contribution = rng.gen_range(fixed!(100_000e18)..=fixed!(100_000_000e18)); alice.fund(contribution).await?; diff --git a/crates/hyperdrive-test-utils/src/chain/deploy.rs b/crates/hyperdrive-test-utils/src/chain/deploy.rs index 831614a6..7f3f8b22 100644 --- a/crates/hyperdrive-test-utils/src/chain/deploy.rs +++ b/crates/hyperdrive-test-utils/src/chain/deploy.rs @@ -226,10 +226,10 @@ impl Default for TestChainConfig { factory_max_position_duration: U256::from(60 * 60 * 24 * 365 * 10), // 10 years factory_min_circuit_breaker_delta: uint256!(0.15e18), factory_max_circuit_breaker_delta: uint256!(2e18), - factory_min_fixed_apr: uint256!(0.01e18), - factory_max_fixed_apr: uint256!(0.5e18), - factory_min_time_stretch_apr: uint256!(0.01e18), - factory_max_time_stretch_apr: uint256!(0.5e18), + factory_min_fixed_apr: uint256!(0), + factory_max_fixed_apr: uint256!(10e18), + factory_min_time_stretch_apr: uint256!(0), + factory_max_time_stretch_apr: uint256!(10e18), factory_min_curve_fee: uint256!(0.0001e18), factory_min_flat_fee: uint256!(0.0001e18), factory_min_governance_lp_fee: uint256!(0.15e18), From af13571ae71a0348ff1f48cec6849485996e7612 Mon Sep 17 00:00:00 2001 From: Mihai Date: Thu, 2 May 2024 12:42:25 -0400 Subject: [PATCH 04/20] make test crash by reverting the fix --- crates/hyperdrive-math/src/short/max.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index 55a18736..ba9495f4 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -436,13 +436,18 @@ impl State { return Ok(None); }; let curve_fee_base = self.open_short_curve_fee(bond_amount)?; + // let share_reserves = self.share_reserves() + // - principal + // + ( + // curve_fee_base + // - self.open_short_governance_fee(bond_amount, Some(curve_fee_base))? + // ) + // / self.vault_share_price(); let share_reserves = self.share_reserves() - - principal - + ( - curve_fee_base - - self.open_short_governance_fee(bond_amount, Some(curve_fee_base))? - ) - / self.vault_share_price(); + - (principal + - (curve_fee_base + - self.open_short_governance_fee(bond_amount, Some(curve_fee_base))?) + / self.vault_share_price()); let exposure = { let checkpoint_exposure: FixedPoint = checkpoint_exposure.max(I256::zero()).try_into()?; From c874cc5cee77be56d7bf3588247177e0db54454d Mon Sep 17 00:00:00 2001 From: Mihai Date: Thu, 2 May 2024 15:42:31 -0400 Subject: [PATCH 05/20] actually make test fail --- crates/hyperdrive-math/src/short/max.rs | 75 ++++++++++++++++++- .../hyperdrive-test-utils/src/chain/deploy.rs | 6 +- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index ba9495f4..f4b513ed 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -1,6 +1,12 @@ use ethers::types::I256; +<<<<<<< HEAD use eyre::{eyre, Result}; use fixed_point::{fixed, FixedPoint}; +======= +use fixed_point::FixedPoint; +use eyre::{eyre, Result}; +use fixed_point_macros::fixed; +>>>>>>> 4ef681e (actually make test fail) use crate::{calculate_effective_share_reserves, State, YieldSpace}; @@ -294,7 +300,12 @@ impl State { optimal_bond_reserves - self.bond_reserves() }; if self +<<<<<<< HEAD .solvency_after_short(absolute_max_bond_amount, checkpoint_exposure)? +======= + .solvency_after_short(absolute_max_bond_amount, spot_price, checkpoint_exposure) + .unwrap() +>>>>>>> 4ef681e (actually make test fail) .is_some() { return Ok(absolute_max_bond_amount); @@ -317,11 +328,21 @@ impl State { // // The guess that we make is very important in determining how quickly // we converge to the solution. +<<<<<<< HEAD let mut max_bond_amount = self.absolute_max_short_guess(spot_price, checkpoint_exposure)?; let mut solvency = match self.solvency_after_short(max_bond_amount, checkpoint_exposure)? { Some(solvency) => solvency, None => return Err(eyre!("Initial guess in `absolute_max_short` is insolvent.")), }; +======= + let mut max_bond_amount = self.absolute_max_short_guess(spot_price, checkpoint_exposure).unwrap(); + let mut maybe_solvency = + self.solvency_after_short(max_bond_amount, spot_price, checkpoint_exposure).unwrap(); + if maybe_solvency.is_none() { + panic!("Initial guess in `absolute_max_short` is insolvent."); + } + let mut solvency = maybe_solvency.unwrap(); +>>>>>>> 4ef681e (actually make test fail) for _ in 0..maybe_max_iterations.unwrap_or(7) { // TODO: It may be better to gracefully handle crossing over the // root by extending the fixed point math library to handle negative @@ -343,6 +364,7 @@ impl State { // If the candidate is insolvent, we've gone too far and can stop // iterating. Otherwise, we update our guess and continue. +<<<<<<< HEAD solvency = match self.solvency_after_short(possible_max_bond_amount, checkpoint_exposure)? { Some(solvency) => { @@ -351,6 +373,19 @@ impl State { } None => break, }; +======= + maybe_solvency = self.solvency_after_short( + possible_max_bond_amount, + spot_price, + checkpoint_exposure, + ).unwrap(); + if let Some(s) = maybe_solvency { + solvency = s; + max_bond_amount = possible_max_bond_amount; + } else { + break; + } +>>>>>>> 4ef681e (actually make test fail) } Ok(max_bond_amount) @@ -449,6 +484,7 @@ impl State { - self.open_short_governance_fee(bond_amount, Some(curve_fee_base))?) / self.vault_share_price()); let exposure = { +<<<<<<< HEAD let checkpoint_exposure: FixedPoint = checkpoint_exposure.max(I256::zero()).try_into()?; // Check for underflow. @@ -462,6 +498,16 @@ impl State { Ok(Some( share_reserves - exposure - self.minimum_share_reserves(), )) +======= + let checkpoint_exposure: FixedPoint = checkpoint_exposure.max(I256::zero()).into(); + if self.long_exposure() <= checkpoint_exposure { + return Err(eyre!("InsufficientLongExposure",)); + } + (self.long_exposure() - checkpoint_exposure) / self.vault_share_price() + }; + if share_reserves >= exposure + self.minimum_share_reserves() { + Ok(Some(share_reserves - exposure - self.minimum_share_reserves())) +>>>>>>> 4ef681e (actually make test fail) } else { Ok(None) } @@ -527,11 +573,24 @@ mod tests { #[tokio::test] async fn fuzz_calculate_max_short_no_budget() -> Result<()> { let chain = TestChain::new().await?; + let mut lowest_rate: Option = None; + let mut highest_rate: Option = None; + + let mut passed_tests = 0; + let mut failed_tests = 0; // Fuzz the rust and solidity implementations against each other. let mut rng = thread_rng(); for _ in 0..*FAST_FUZZ_RUNS { let state = rng.gen::(); + let fixed_rate = state.calculate_spot_rate(); + if lowest_rate.is_none() || fixed_rate < lowest_rate.unwrap() { + lowest_rate = Some(fixed_rate); + } + if highest_rate.is_none() || fixed_rate > highest_rate.unwrap() { + highest_rate = Some(fixed_rate); + } + println!("Fixed rate: {}", fixed_rate); let checkpoint_exposure = { let value = rng.gen_range(fixed!(0)..=FixedPoint::try_from(I256::MAX)?); if rng.gen() { @@ -576,6 +635,7 @@ mod tests { .await { Ok(expected) => { +<<<<<<< HEAD // TODO: remove this tolerance when calculate_open_short // rust implementation matches solidity. // Currently, only about 1 - 4 / 1000 tests aren't @@ -590,6 +650,20 @@ mod tests { assert!(actual.is_err() || actual.unwrap().is_err()); } }; +======= + passed_tests += 1; + assert_eq!(actual.unwrap(), FixedPoint::from(expected)); + } + Err(expected) => { + failed_tests += 1; + println!("Test failed: actual: {:?} expected: {:?}", actual, expected); + assert!(actual.is_err()); + } + } // end for loop + let total_tests = failed_tests + passed_tests; + let failure_rate = failed_tests as f64 / total_tests as f64; + println!("Total tests: {} Passed: {} Failed: {}, Failure rate: {}", total_tests, passed_tests, failed_tests, failure_rate); +>>>>>>> 4ef681e (actually make test fail) } Ok(()) } @@ -615,7 +689,6 @@ mod tests { // Fund Alice and Bob. let fixed_rate = rng.gen_range(fixed!(0.01e18)..=fixed!(1e18)); - println!("Fixed rate: {}", fixed_rate); let contribution = rng.gen_range(fixed!(100_000e18)..=fixed!(100_000_000e18)); alice.fund(contribution).await?; diff --git a/crates/hyperdrive-test-utils/src/chain/deploy.rs b/crates/hyperdrive-test-utils/src/chain/deploy.rs index 7f3f8b22..2c39a788 100644 --- a/crates/hyperdrive-test-utils/src/chain/deploy.rs +++ b/crates/hyperdrive-test-utils/src/chain/deploy.rs @@ -342,9 +342,9 @@ impl TestnetDeploy for Chain { sweep_collector: client.address(), governance: client.address(), fees: Fees { - curve: uint256!(0.05e18), - flat: uint256!(0.0005e18), - governance_lp: uint256!(0.15e18), + curve: uint256!(0.01e18), + flat: uint256!(0e18), + governance_lp: uint256!(0.1e18), governance_zombie: uint256!(0.15e18), }, }; From 793cd15844442e4148c6c718c4916ed52e71b024 Mon Sep 17 00:00:00 2001 From: Mihai Date: Sat, 1 Jun 2024 01:43:54 -0400 Subject: [PATCH 06/20] fix rebase --- crates/hyperdrive-math/src/short/max.rs | 63 ++----------------------- 1 file changed, 4 insertions(+), 59 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index f4b513ed..f0268ced 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -1,12 +1,6 @@ use ethers::types::I256; -<<<<<<< HEAD use eyre::{eyre, Result}; use fixed_point::{fixed, FixedPoint}; -======= -use fixed_point::FixedPoint; -use eyre::{eyre, Result}; -use fixed_point_macros::fixed; ->>>>>>> 4ef681e (actually make test fail) use crate::{calculate_effective_share_reserves, State, YieldSpace}; @@ -300,12 +294,7 @@ impl State { optimal_bond_reserves - self.bond_reserves() }; if self -<<<<<<< HEAD .solvency_after_short(absolute_max_bond_amount, checkpoint_exposure)? -======= - .solvency_after_short(absolute_max_bond_amount, spot_price, checkpoint_exposure) - .unwrap() ->>>>>>> 4ef681e (actually make test fail) .is_some() { return Ok(absolute_max_bond_amount); @@ -328,21 +317,11 @@ impl State { // // The guess that we make is very important in determining how quickly // we converge to the solution. -<<<<<<< HEAD let mut max_bond_amount = self.absolute_max_short_guess(spot_price, checkpoint_exposure)?; let mut solvency = match self.solvency_after_short(max_bond_amount, checkpoint_exposure)? { Some(solvency) => solvency, None => return Err(eyre!("Initial guess in `absolute_max_short` is insolvent.")), }; -======= - let mut max_bond_amount = self.absolute_max_short_guess(spot_price, checkpoint_exposure).unwrap(); - let mut maybe_solvency = - self.solvency_after_short(max_bond_amount, spot_price, checkpoint_exposure).unwrap(); - if maybe_solvency.is_none() { - panic!("Initial guess in `absolute_max_short` is insolvent."); - } - let mut solvency = maybe_solvency.unwrap(); ->>>>>>> 4ef681e (actually make test fail) for _ in 0..maybe_max_iterations.unwrap_or(7) { // TODO: It may be better to gracefully handle crossing over the // root by extending the fixed point math library to handle negative @@ -364,7 +343,6 @@ impl State { // If the candidate is insolvent, we've gone too far and can stop // iterating. Otherwise, we update our guess and continue. -<<<<<<< HEAD solvency = match self.solvency_after_short(possible_max_bond_amount, checkpoint_exposure)? { Some(solvency) => { @@ -373,19 +351,6 @@ impl State { } None => break, }; -======= - maybe_solvency = self.solvency_after_short( - possible_max_bond_amount, - spot_price, - checkpoint_exposure, - ).unwrap(); - if let Some(s) = maybe_solvency { - solvency = s; - max_bond_amount = possible_max_bond_amount; - } else { - break; - } ->>>>>>> 4ef681e (actually make test fail) } Ok(max_bond_amount) @@ -484,7 +449,6 @@ impl State { - self.open_short_governance_fee(bond_amount, Some(curve_fee_base))?) / self.vault_share_price()); let exposure = { -<<<<<<< HEAD let checkpoint_exposure: FixedPoint = checkpoint_exposure.max(I256::zero()).try_into()?; // Check for underflow. @@ -498,16 +462,6 @@ impl State { Ok(Some( share_reserves - exposure - self.minimum_share_reserves(), )) -======= - let checkpoint_exposure: FixedPoint = checkpoint_exposure.max(I256::zero()).into(); - if self.long_exposure() <= checkpoint_exposure { - return Err(eyre!("InsufficientLongExposure",)); - } - (self.long_exposure() - checkpoint_exposure) / self.vault_share_price() - }; - if share_reserves >= exposure + self.minimum_share_reserves() { - Ok(Some(share_reserves - exposure - self.minimum_share_reserves())) ->>>>>>> 4ef681e (actually make test fail) } else { Ok(None) } @@ -635,35 +589,26 @@ mod tests { .await { Ok(expected) => { -<<<<<<< HEAD // TODO: remove this tolerance when calculate_open_short // rust implementation matches solidity. // Currently, only about 1 - 4 / 1000 tests aren't - // exact matchces. Related issue: + // exact matches. Related issue: // https://github.com/delvtech/hyperdrive-rs/issues/45 + passed_tests += 1; assert_eq!( U256::from(actual.unwrap().unwrap()) / uint256!(1e12), expected / uint256!(1e12) ); } - Err(_) => { - assert!(actual.is_err() || actual.unwrap().is_err()); - } - }; -======= - passed_tests += 1; - assert_eq!(actual.unwrap(), FixedPoint::from(expected)); - } Err(expected) => { failed_tests += 1; println!("Test failed: actual: {:?} expected: {:?}", actual, expected); - assert!(actual.is_err()); + assert!(actual.is_err() || actual.unwrap().is_err()); } - } // end for loop + }; let total_tests = failed_tests + passed_tests; let failure_rate = failed_tests as f64 / total_tests as f64; println!("Total tests: {} Passed: {} Failed: {}, Failure rate: {}", total_tests, passed_tests, failed_tests, failure_rate); ->>>>>>> 4ef681e (actually make test fail) } Ok(()) } From 27cf37b45c6df678f55b74926f0b2b5e58dba262 Mon Sep 17 00:00:00 2001 From: Mihai Date: Sat, 1 Jun 2024 01:53:13 -0400 Subject: [PATCH 07/20] unwrap fixed rate --- crates/hyperdrive-math/src/short/max.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index f0268ced..a134a1cf 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -544,7 +544,7 @@ mod tests { if highest_rate.is_none() || fixed_rate > highest_rate.unwrap() { highest_rate = Some(fixed_rate); } - println!("Fixed rate: {}", fixed_rate); + println!("Fixed rate: {}", fixed_rate.expect("Failed to get fixed rate")); let checkpoint_exposure = { let value = rng.gen_range(fixed!(0)..=FixedPoint::try_from(I256::MAX)?); if rng.gen() { From 4d9f3bf4cd48bada6a5a85479773a07f4ee031d4 Mon Sep 17 00:00:00 2001 From: Mihai Date: Sat, 1 Jun 2024 01:54:44 -0400 Subject: [PATCH 08/20] cargo fmt --- crates/hyperdrive-math/src/short/max.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index a134a1cf..5a907db0 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -544,7 +544,10 @@ mod tests { if highest_rate.is_none() || fixed_rate > highest_rate.unwrap() { highest_rate = Some(fixed_rate); } - println!("Fixed rate: {}", fixed_rate.expect("Failed to get fixed rate")); + println!( + "Fixed rate: {}", + fixed_rate.expect("Failed to get fixed rate") + ); let checkpoint_exposure = { let value = rng.gen_range(fixed!(0)..=FixedPoint::try_from(I256::MAX)?); if rng.gen() { @@ -608,7 +611,10 @@ mod tests { }; let total_tests = failed_tests + passed_tests; let failure_rate = failed_tests as f64 / total_tests as f64; - println!("Total tests: {} Passed: {} Failed: {}, Failure rate: {}", total_tests, passed_tests, failed_tests, failure_rate); + println!( + "Total tests: {} Passed: {} Failed: {}, Failure rate: {}", + total_tests, passed_tests, failed_tests, failure_rate + ); } Ok(()) } From 38a7359c5fac8b65142f2ddd6de47f9f62eed9c7 Mon Sep 17 00:00:00 2001 From: Mihai Date: Sat, 1 Jun 2024 09:53:18 -0400 Subject: [PATCH 09/20] unwrap fixed rate properly --- crates/hyperdrive-math/src/short/max.rs | 7 ++----- rust-toolchain.toml | 2 ++ 2 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 rust-toolchain.toml diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index 5a907db0..e936d7d7 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -537,17 +537,14 @@ mod tests { let mut rng = thread_rng(); for _ in 0..*FAST_FUZZ_RUNS { let state = rng.gen::(); - let fixed_rate = state.calculate_spot_rate(); + let fixed_rate = state.calculate_spot_rate().expect("Failed to get fixed rate"); if lowest_rate.is_none() || fixed_rate < lowest_rate.unwrap() { lowest_rate = Some(fixed_rate); } if highest_rate.is_none() || fixed_rate > highest_rate.unwrap() { highest_rate = Some(fixed_rate); } - println!( - "Fixed rate: {}", - fixed_rate.expect("Failed to get fixed rate") - ); + println!("Fixed rate: {}", fixed_rate); let checkpoint_exposure = { let value = rng.gen_range(fixed!(0)..=FixedPoint::try_from(I256::MAX)?); if rng.gen() { diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..292fe499 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" From 806328f5896a2aea60070946b75a276026e249a8 Mon Sep 17 00:00:00 2001 From: Mihai Date: Sat, 1 Jun 2024 10:15:16 -0400 Subject: [PATCH 10/20] fmt and remove unstable features --- crates/hyperdrive-math/src/short/max.rs | 4 +++- rustfmt.toml | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index e936d7d7..74b0a474 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -537,7 +537,9 @@ mod tests { let mut rng = thread_rng(); for _ in 0..*FAST_FUZZ_RUNS { let state = rng.gen::(); - let fixed_rate = state.calculate_spot_rate().expect("Failed to get fixed rate"); + let fixed_rate = state + .calculate_spot_rate() + .expect("Failed to get fixed rate"); if lowest_rate.is_none() || fixed_rate < lowest_rate.unwrap() { lowest_rate = Some(fixed_rate); } diff --git a/rustfmt.toml b/rustfmt.toml index 38aa0c67..44148a2d 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1 @@ -unstable_features = true -imports_granularity = "Crate" -group_imports = "StdExternalCrate" reorder_imports = true From 72b5911c33693853090c2750f8658461250cbc54 Mon Sep 17 00:00:00 2001 From: Mihai Date: Sat, 1 Jun 2024 10:51:45 -0400 Subject: [PATCH 11/20] increase minimum fixed rate to 1bps --- crates/hyperdrive-test-utils/src/chain/deploy.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/hyperdrive-test-utils/src/chain/deploy.rs b/crates/hyperdrive-test-utils/src/chain/deploy.rs index 2c39a788..00d11ff2 100644 --- a/crates/hyperdrive-test-utils/src/chain/deploy.rs +++ b/crates/hyperdrive-test-utils/src/chain/deploy.rs @@ -226,7 +226,7 @@ impl Default for TestChainConfig { factory_max_position_duration: U256::from(60 * 60 * 24 * 365 * 10), // 10 years factory_min_circuit_breaker_delta: uint256!(0.15e18), factory_max_circuit_breaker_delta: uint256!(2e18), - factory_min_fixed_apr: uint256!(0), + factory_min_fixed_apr: uint256!(0.001*1e18), factory_max_fixed_apr: uint256!(10e18), factory_min_time_stretch_apr: uint256!(0), factory_max_time_stretch_apr: uint256!(10e18), From 06a9c6d7cdbb1fd00a6a3ec219dc9762e5f67eed Mon Sep 17 00:00:00 2001 From: Mihai Date: Sat, 1 Jun 2024 11:12:31 -0400 Subject: [PATCH 12/20] cargo fmt --- crates/hyperdrive-test-utils/src/chain/deploy.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/hyperdrive-test-utils/src/chain/deploy.rs b/crates/hyperdrive-test-utils/src/chain/deploy.rs index 00d11ff2..8994dfab 100644 --- a/crates/hyperdrive-test-utils/src/chain/deploy.rs +++ b/crates/hyperdrive-test-utils/src/chain/deploy.rs @@ -226,7 +226,7 @@ impl Default for TestChainConfig { factory_max_position_duration: U256::from(60 * 60 * 24 * 365 * 10), // 10 years factory_min_circuit_breaker_delta: uint256!(0.15e18), factory_max_circuit_breaker_delta: uint256!(2e18), - factory_min_fixed_apr: uint256!(0.001*1e18), + factory_min_fixed_apr: uint256!(0.001 * 1e18), factory_max_fixed_apr: uint256!(10e18), factory_min_time_stretch_apr: uint256!(0), factory_max_time_stretch_apr: uint256!(10e18), From e8252380427f4f00afcaab2bad386bd14259293c Mon Sep 17 00:00:00 2001 From: Mihai Date: Mon, 3 Jun 2024 12:39:11 -0400 Subject: [PATCH 13/20] better logging to show tests actually pass correctly --- crates/hyperdrive-math/src/short/max.rs | 30 +++++++++++-------- .../hyperdrive-test-utils/src/chain/deploy.rs | 2 +- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index 74b0a474..c8b69833 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -530,8 +530,9 @@ mod tests { let mut lowest_rate: Option = None; let mut highest_rate: Option = None; - let mut passed_tests = 0; - let mut failed_tests = 0; + let mut both_pass_tests = 0; + let mut both_fail_tests = 0; + let mut mismatched_tests = 0; // Fuzz the rust and solidity implementations against each other. let mut rng = thread_rng(); @@ -596,23 +597,28 @@ mod tests { // Currently, only about 1 - 4 / 1000 tests aren't // exact matches. Related issue: // https://github.com/delvtech/hyperdrive-rs/issues/45 - passed_tests += 1; assert_eq!( U256::from(actual.unwrap().unwrap()) / uint256!(1e12), expected / uint256!(1e12) ); + both_pass_tests += 1; } - Err(expected) => { - failed_tests += 1; - println!("Test failed: actual: {:?} expected: {:?}", actual, expected); - assert!(actual.is_err() || actual.unwrap().is_err()); - } + Err(expected) => match actual { + Err(_) => { + both_fail_tests += 1; + println!("Both failed: actual: {:?} expected: {:?}", actual, expected); + }, + Ok(_) => { + mismatched_tests += 1; + println!("MISMATCHED: actual: {:?} expected: {:?}", actual, expected); + }, + }, }; - let total_tests = failed_tests + passed_tests; - let failure_rate = failed_tests as f64 / total_tests as f64; + let total_tests = both_pass_tests + both_fail_tests + mismatched_tests; + let failure_rate = mismatched_tests as f64 / total_tests as f64; println!( - "Total tests: {} Passed: {} Failed: {}, Failure rate: {}", - total_tests, passed_tests, failed_tests, failure_rate + "Total tests: {} Both pass: {} Both fail: {} Mismatched: {} Failure rate: {}", + total_tests, both_pass_tests, both_fail_tests, mismatched_tests, failure_rate ); } Ok(()) diff --git a/crates/hyperdrive-test-utils/src/chain/deploy.rs b/crates/hyperdrive-test-utils/src/chain/deploy.rs index 8994dfab..6249157c 100644 --- a/crates/hyperdrive-test-utils/src/chain/deploy.rs +++ b/crates/hyperdrive-test-utils/src/chain/deploy.rs @@ -226,7 +226,7 @@ impl Default for TestChainConfig { factory_max_position_duration: U256::from(60 * 60 * 24 * 365 * 10), // 10 years factory_min_circuit_breaker_delta: uint256!(0.15e18), factory_max_circuit_breaker_delta: uint256!(2e18), - factory_min_fixed_apr: uint256!(0.001 * 1e18), + factory_min_fixed_apr: uint256!(0.1e18), factory_max_fixed_apr: uint256!(10e18), factory_min_time_stretch_apr: uint256!(0), factory_max_time_stretch_apr: uint256!(10e18), From 64582d106f2b4b827c0e4814fcf3c46b8f998475 Mon Sep 17 00:00:00 2001 From: Mihai Date: Mon, 3 Jun 2024 12:55:35 -0400 Subject: [PATCH 14/20] fuzz fixed rate down to 1bps --- crates/hyperdrive-math/src/short/max.rs | 2 +- .../hyperdrive-test-utils/src/chain/deploy.rs | 32 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index c8b69833..d9049aaa 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -644,7 +644,7 @@ mod tests { let id = chain.snapshot().await?; // Fund Alice and Bob. - let fixed_rate = rng.gen_range(fixed!(0.01e18)..=fixed!(1e18)); + let fixed_rate = rng.gen_range(fixed!(0.0001e18)..=fixed!(1e18)); // 0.01% to 100% let contribution = rng.gen_range(fixed!(100_000e18)..=fixed!(100_000_000e18)); alice.fund(contribution).await?; diff --git a/crates/hyperdrive-test-utils/src/chain/deploy.rs b/crates/hyperdrive-test-utils/src/chain/deploy.rs index 6249157c..37d3f82a 100644 --- a/crates/hyperdrive-test-utils/src/chain/deploy.rs +++ b/crates/hyperdrive-test-utils/src/chain/deploy.rs @@ -219,23 +219,23 @@ impl Default for TestChainConfig { // lido configuration lido_starting_rate: uint256!(0.035e18), // factory configuration - factory_checkpoint_duration_resolution: U256::from(60 * 60), // 1 hour - factory_min_checkpoint_duration: U256::from(60 * 60), // 1 hour - factory_max_checkpoint_duration: U256::from(60 * 60 * 24), // 1 day - factory_min_position_duration: U256::from(60 * 60 * 24 * 7), // 7 days + factory_checkpoint_duration_resolution: U256::from(60 * 60), // 1 hour + factory_min_checkpoint_duration: U256::from(60 * 60), // 1 hour + factory_max_checkpoint_duration: U256::from(60 * 60 * 24), // 1 day + factory_min_position_duration: U256::from(60 * 60 * 24 * 7), // 7 days factory_max_position_duration: U256::from(60 * 60 * 24 * 365 * 10), // 10 years factory_min_circuit_breaker_delta: uint256!(0.15e18), factory_max_circuit_breaker_delta: uint256!(2e18), - factory_min_fixed_apr: uint256!(0.1e18), - factory_max_fixed_apr: uint256!(10e18), - factory_min_time_stretch_apr: uint256!(0), - factory_max_time_stretch_apr: uint256!(10e18), - factory_min_curve_fee: uint256!(0.0001e18), - factory_min_flat_fee: uint256!(0.0001e18), + factory_min_fixed_apr: uint256!(0.0001e18), // 0.01% or 1bps + factory_max_fixed_apr: uint256!(10e18), // 1000% + factory_min_time_stretch_apr: uint256!(0), // 0% + factory_max_time_stretch_apr: uint256!(10e18), // 1000% + factory_min_curve_fee: uint256!(0.0001e18), // 0.01% + factory_min_flat_fee: uint256!(0.0001e18), // 0.01% factory_min_governance_lp_fee: uint256!(0.15e18), factory_min_governance_zombie_fee: uint256!(0.03e18), - factory_max_curve_fee: uint256!(0.1e18), - factory_max_flat_fee: uint256!(0.001e18), + factory_max_curve_fee: uint256!(0.1e18), // 10% + factory_max_flat_fee: uint256!(0.001e18), // 0.1% factory_max_governance_lp_fee: uint256!(0.15e18), factory_max_governance_zombie_fee: uint256!(0.03e18), // erc4626 hyperdrive configuration @@ -248,7 +248,7 @@ impl Default for TestChainConfig { erc4626_hyperdrive_position_duration: U256::from(60 * 60 * 24 * 7), // 7 days erc4626_hyperdrive_checkpoint_duration: U256::from(60 * 60), // 1 hour erc4626_hyperdrive_curve_fee: uint256!(0.01e18), - erc4626_hyperdrive_flat_fee: uint256!(0.0005e18) / uint256!(52), // 0.05% APR + erc4626_hyperdrive_flat_fee: uint256!(0.0005e18) / uint256!(52), // 0.05% APR erc4626_hyperdrive_governance_lp_fee: uint256!(0.15e18), erc4626_hyperdrive_governance_zombie_fee: uint256!(0.03e18), // steth hyperdrive configuration @@ -258,10 +258,10 @@ impl Default for TestChainConfig { steth_hyperdrive_minimum_share_reserves: uint256!(1e15), steth_hyperdrive_minimum_transaction_amount: uint256!(1e15), steth_hyperdrive_circuit_breaker_delta: uint256!(2e18), - steth_hyperdrive_position_duration: U256::from(60 * 60 * 24 * 7), // 7 days - steth_hyperdrive_checkpoint_duration: U256::from(60 * 60), // 1 hour + steth_hyperdrive_position_duration: U256::from(60 * 60 * 24 * 7), // 7 days + steth_hyperdrive_checkpoint_duration: U256::from(60 * 60), // 1 hour steth_hyperdrive_curve_fee: uint256!(0.01e18), - steth_hyperdrive_flat_fee: uint256!(0.0005e18) / uint256!(52), // 0.05% APR + steth_hyperdrive_flat_fee: uint256!(0.0005e18) / uint256!(52), // 0.05% APR steth_hyperdrive_governance_lp_fee: uint256!(0.15e18), steth_hyperdrive_governance_zombie_fee: uint256!(0.03e18), } From 3144a382bc72ebdeaff4aeefdff92534d036cc5e Mon Sep 17 00:00:00 2001 From: Mihai Date: Mon, 3 Jun 2024 13:27:08 -0400 Subject: [PATCH 15/20] revert fee change --- crates/hyperdrive-math/src/short/max.rs | 1 + crates/hyperdrive-test-utils/src/chain/deploy.rs | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index d9049aaa..17fcfc09 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -620,6 +620,7 @@ mod tests { "Total tests: {} Both pass: {} Both fail: {} Mismatched: {} Failure rate: {}", total_tests, both_pass_tests, both_fail_tests, mismatched_tests, failure_rate ); + println!("Fuzzed over fixed rate from {:?} to {:?}", lowest_rate, highest_rate); } Ok(()) } diff --git a/crates/hyperdrive-test-utils/src/chain/deploy.rs b/crates/hyperdrive-test-utils/src/chain/deploy.rs index 37d3f82a..043f617a 100644 --- a/crates/hyperdrive-test-utils/src/chain/deploy.rs +++ b/crates/hyperdrive-test-utils/src/chain/deploy.rs @@ -226,7 +226,7 @@ impl Default for TestChainConfig { factory_max_position_duration: U256::from(60 * 60 * 24 * 365 * 10), // 10 years factory_min_circuit_breaker_delta: uint256!(0.15e18), factory_max_circuit_breaker_delta: uint256!(2e18), - factory_min_fixed_apr: uint256!(0.0001e18), // 0.01% or 1bps + factory_min_fixed_apr: uint256!(0), // 0% factory_max_fixed_apr: uint256!(10e18), // 1000% factory_min_time_stretch_apr: uint256!(0), // 0% factory_max_time_stretch_apr: uint256!(10e18), // 1000% @@ -342,9 +342,9 @@ impl TestnetDeploy for Chain { sweep_collector: client.address(), governance: client.address(), fees: Fees { - curve: uint256!(0.01e18), - flat: uint256!(0e18), - governance_lp: uint256!(0.1e18), + curve: uint256!(0.05e18), + flat: uint256!(0.0005e18), + governance_lp: uint256!(0.15e18), governance_zombie: uint256!(0.15e18), }, }; From b6421a7be07098ec7069c49f8441edc38dfe2153 Mon Sep 17 00:00:00 2001 From: Mihai Date: Mon, 3 Jun 2024 13:42:31 -0400 Subject: [PATCH 16/20] cargo fmt --- crates/hyperdrive-math/src/short/max.rs | 11 ++++--- .../hyperdrive-test-utils/src/chain/deploy.rs | 32 +++++++++---------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index 17fcfc09..17a55da4 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -607,11 +607,11 @@ mod tests { Err(_) => { both_fail_tests += 1; println!("Both failed: actual: {:?} expected: {:?}", actual, expected); - }, + } Ok(_) => { mismatched_tests += 1; println!("MISMATCHED: actual: {:?} expected: {:?}", actual, expected); - }, + } }, }; let total_tests = both_pass_tests + both_fail_tests + mismatched_tests; @@ -620,7 +620,10 @@ mod tests { "Total tests: {} Both pass: {} Both fail: {} Mismatched: {} Failure rate: {}", total_tests, both_pass_tests, both_fail_tests, mismatched_tests, failure_rate ); - println!("Fuzzed over fixed rate from {:?} to {:?}", lowest_rate, highest_rate); + println!( + "Fuzzed over fixed rate from {:?} to {:?}", + lowest_rate, highest_rate + ); } Ok(()) } @@ -645,7 +648,7 @@ mod tests { let id = chain.snapshot().await?; // Fund Alice and Bob. - let fixed_rate = rng.gen_range(fixed!(0.0001e18)..=fixed!(1e18)); // 0.01% to 100% + let fixed_rate = rng.gen_range(fixed!(0.0001e18)..=fixed!(1e18)); // 0.01% to 100% let contribution = rng.gen_range(fixed!(100_000e18)..=fixed!(100_000_000e18)); alice.fund(contribution).await?; diff --git a/crates/hyperdrive-test-utils/src/chain/deploy.rs b/crates/hyperdrive-test-utils/src/chain/deploy.rs index 043f617a..32c4063d 100644 --- a/crates/hyperdrive-test-utils/src/chain/deploy.rs +++ b/crates/hyperdrive-test-utils/src/chain/deploy.rs @@ -219,23 +219,23 @@ impl Default for TestChainConfig { // lido configuration lido_starting_rate: uint256!(0.035e18), // factory configuration - factory_checkpoint_duration_resolution: U256::from(60 * 60), // 1 hour - factory_min_checkpoint_duration: U256::from(60 * 60), // 1 hour - factory_max_checkpoint_duration: U256::from(60 * 60 * 24), // 1 day - factory_min_position_duration: U256::from(60 * 60 * 24 * 7), // 7 days + factory_checkpoint_duration_resolution: U256::from(60 * 60), // 1 hour + factory_min_checkpoint_duration: U256::from(60 * 60), // 1 hour + factory_max_checkpoint_duration: U256::from(60 * 60 * 24), // 1 day + factory_min_position_duration: U256::from(60 * 60 * 24 * 7), // 7 days factory_max_position_duration: U256::from(60 * 60 * 24 * 365 * 10), // 10 years factory_min_circuit_breaker_delta: uint256!(0.15e18), factory_max_circuit_breaker_delta: uint256!(2e18), - factory_min_fixed_apr: uint256!(0), // 0% - factory_max_fixed_apr: uint256!(10e18), // 1000% - factory_min_time_stretch_apr: uint256!(0), // 0% - factory_max_time_stretch_apr: uint256!(10e18), // 1000% - factory_min_curve_fee: uint256!(0.0001e18), // 0.01% - factory_min_flat_fee: uint256!(0.0001e18), // 0.01% + factory_min_fixed_apr: uint256!(0), // 0% + factory_max_fixed_apr: uint256!(10e18), // 1000% + factory_min_time_stretch_apr: uint256!(0), // 0% + factory_max_time_stretch_apr: uint256!(10e18), // 1000% + factory_min_curve_fee: uint256!(0.0001e18), // 0.01% + factory_min_flat_fee: uint256!(0.0001e18), // 0.01% factory_min_governance_lp_fee: uint256!(0.15e18), factory_min_governance_zombie_fee: uint256!(0.03e18), - factory_max_curve_fee: uint256!(0.1e18), // 10% - factory_max_flat_fee: uint256!(0.001e18), // 0.1% + factory_max_curve_fee: uint256!(0.1e18), // 10% + factory_max_flat_fee: uint256!(0.001e18), // 0.1% factory_max_governance_lp_fee: uint256!(0.15e18), factory_max_governance_zombie_fee: uint256!(0.03e18), // erc4626 hyperdrive configuration @@ -248,7 +248,7 @@ impl Default for TestChainConfig { erc4626_hyperdrive_position_duration: U256::from(60 * 60 * 24 * 7), // 7 days erc4626_hyperdrive_checkpoint_duration: U256::from(60 * 60), // 1 hour erc4626_hyperdrive_curve_fee: uint256!(0.01e18), - erc4626_hyperdrive_flat_fee: uint256!(0.0005e18) / uint256!(52), // 0.05% APR + erc4626_hyperdrive_flat_fee: uint256!(0.0005e18) / uint256!(52), // 0.05% APR erc4626_hyperdrive_governance_lp_fee: uint256!(0.15e18), erc4626_hyperdrive_governance_zombie_fee: uint256!(0.03e18), // steth hyperdrive configuration @@ -258,10 +258,10 @@ impl Default for TestChainConfig { steth_hyperdrive_minimum_share_reserves: uint256!(1e15), steth_hyperdrive_minimum_transaction_amount: uint256!(1e15), steth_hyperdrive_circuit_breaker_delta: uint256!(2e18), - steth_hyperdrive_position_duration: U256::from(60 * 60 * 24 * 7), // 7 days - steth_hyperdrive_checkpoint_duration: U256::from(60 * 60), // 1 hour + steth_hyperdrive_position_duration: U256::from(60 * 60 * 24 * 7), // 7 days + steth_hyperdrive_checkpoint_duration: U256::from(60 * 60), // 1 hour steth_hyperdrive_curve_fee: uint256!(0.01e18), - steth_hyperdrive_flat_fee: uint256!(0.0005e18) / uint256!(52), // 0.05% APR + steth_hyperdrive_flat_fee: uint256!(0.0005e18) / uint256!(52), // 0.05% APR steth_hyperdrive_governance_lp_fee: uint256!(0.15e18), steth_hyperdrive_governance_zombie_fee: uint256!(0.03e18), } From cfdc4630a03c7c148fcaaaa61bfaade57dbe8c7b Mon Sep 17 00:00:00 2001 From: Mihai Date: Mon, 3 Jun 2024 13:50:12 -0400 Subject: [PATCH 17/20] better printouts --- crates/hyperdrive-math/src/short/max.rs | 29 +++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index 17a55da4..9135ad0e 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -436,18 +436,13 @@ impl State { return Ok(None); }; let curve_fee_base = self.open_short_curve_fee(bond_amount)?; - // let share_reserves = self.share_reserves() - // - principal - // + ( - // curve_fee_base - // - self.open_short_governance_fee(bond_amount, Some(curve_fee_base))? - // ) - // / self.vault_share_price(); let share_reserves = self.share_reserves() - - (principal - - (curve_fee_base - - self.open_short_governance_fee(bond_amount, Some(curve_fee_base))?) - / self.vault_share_price()); + - principal + + ( + curve_fee_base + - self.open_short_governance_fee(bond_amount, Some(curve_fee_base))? + ) + / self.vault_share_price(); let exposure = { let checkpoint_exposure: FixedPoint = checkpoint_exposure.max(I256::zero()).try_into()?; @@ -529,6 +524,8 @@ mod tests { let chain = TestChain::new().await?; let mut lowest_rate: Option = None; let mut highest_rate: Option = None; + let mut lowest_rate_mismatch: Option = None; + let mut highest_rate_mismatch: Option = None; let mut both_pass_tests = 0; let mut both_fail_tests = 0; @@ -611,6 +608,12 @@ mod tests { Ok(_) => { mismatched_tests += 1; println!("MISMATCHED: actual: {:?} expected: {:?}", actual, expected); + if lowest_rate_mismatch.is_none() || fixed_rate < lowest_rate_mismatch.unwrap() { + lowest_rate_mismatch = Some(fixed_rate); + } + if highest_rate_mismatch.is_none() || fixed_rate > highest_rate_mismatch.unwrap() { + highest_rate_mismatch = Some(fixed_rate); + } } }, }; @@ -624,6 +627,10 @@ mod tests { "Fuzzed over fixed rate from {:?} to {:?}", lowest_rate, highest_rate ); + println!( + "Mismatched fixed rate from {:?} to {:?}", + lowest_rate_mismatch, highest_rate_mismatch + ); } Ok(()) } From b991efc76677dc6c59ad5c6dc2a94d964f9624e2 Mon Sep 17 00:00:00 2001 From: Mihai Date: Mon, 3 Jun 2024 17:12:53 -0400 Subject: [PATCH 18/20] gen state with effective_share_reserves --- crates/hyperdrive-math/src/lib.rs | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/crates/hyperdrive-math/src/lib.rs b/crates/hyperdrive-math/src/lib.rs index 52ebf06f..87d41ff7 100644 --- a/crates/hyperdrive-math/src/lib.rs +++ b/crates/hyperdrive-math/src/lib.rs @@ -65,13 +65,27 @@ impl Distribution for Standard { // We need the spot price to be less than or equal to 1, so we need to // generate the bond reserves so that mu * z <= y let share_reserves = rng.gen_range(fixed!(1_000e18)..=fixed!(100_000_000e18)); + let share_adjustment = { + if rng.gen() { + -I256::try_from(rng.gen_range(fixed!(0)..=fixed!(100_000e18))).unwrap() + } else { + // We generate values that satisfy `z - zeta >= z_min`, + // so `z - z_min >= zeta`. + I256::try_from(rng.gen_range( + fixed!(0)..(share_reserves - FixedPoint::from(config.minimum_share_reserves)), + )) + .unwrap() + } + }; + let effective_share_reserves = + calculate_effective_share_reserves(share_reserves, share_adjustment).unwrap(); let info = PoolInfo { share_reserves: share_reserves.into(), zombie_base_proceeds: fixed!(0).into(), zombie_share_reserves: fixed!(0).into(), bond_reserves: rng .gen_range( - share_reserves * FixedPoint::from(config.initial_vault_share_price) + effective_share_reserves * FixedPoint::from(config.initial_vault_share_price) ..=fixed!(1_000_000_000e18), ) .into(), @@ -79,19 +93,7 @@ impl Distribution for Standard { longs_outstanding: rng.gen_range(fixed!(0)..=fixed!(100_000e18)).into(), shorts_outstanding: rng.gen_range(fixed!(0)..=fixed!(100_000e18)).into(), long_exposure: rng.gen_range(fixed!(0)..=fixed!(100_000e18)).into(), - share_adjustment: { - if rng.gen() { - -I256::try_from(rng.gen_range(fixed!(0)..=fixed!(100_000e18))).unwrap() - } else { - // We generate values that satisfy `z - zeta >= z_min`, - // so `z - z_min >= zeta`. - I256::try_from(rng.gen_range( - fixed!(0) - ..(share_reserves - FixedPoint::from(config.minimum_share_reserves)), - )) - .unwrap() - } - }, + share_adjustment: share_adjustment.into(), // If this range returns greater than position duration, then both rust and solidity will fail // on calls that depend on this value. long_average_maturity_time: rng From eb240ae9a6f9b49d8e10136a745f6b0895929b49 Mon Sep 17 00:00:00 2001 From: Mihai Date: Mon, 3 Jun 2024 17:18:10 -0400 Subject: [PATCH 19/20] cargo fmt --- crates/hyperdrive-math/src/short/max.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index 9135ad0e..aec4c1dc 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -436,13 +436,10 @@ impl State { return Ok(None); }; let curve_fee_base = self.open_short_curve_fee(bond_amount)?; - let share_reserves = self.share_reserves() - - principal - + ( - curve_fee_base - - self.open_short_governance_fee(bond_amount, Some(curve_fee_base))? - ) - / self.vault_share_price(); + let share_reserves = self.share_reserves() - principal + + (curve_fee_base + - self.open_short_governance_fee(bond_amount, Some(curve_fee_base))?) + / self.vault_share_price(); let exposure = { let checkpoint_exposure: FixedPoint = checkpoint_exposure.max(I256::zero()).try_into()?; @@ -608,10 +605,14 @@ mod tests { Ok(_) => { mismatched_tests += 1; println!("MISMATCHED: actual: {:?} expected: {:?}", actual, expected); - if lowest_rate_mismatch.is_none() || fixed_rate < lowest_rate_mismatch.unwrap() { + if lowest_rate_mismatch.is_none() + || fixed_rate < lowest_rate_mismatch.unwrap() + { lowest_rate_mismatch = Some(fixed_rate); } - if highest_rate_mismatch.is_none() || fixed_rate > highest_rate_mismatch.unwrap() { + if highest_rate_mismatch.is_none() + || fixed_rate > highest_rate_mismatch.unwrap() + { highest_rate_mismatch = Some(fixed_rate); } } From 989ad42c89e4b9179331f8b879e376a356433bca Mon Sep 17 00:00:00 2001 From: Mihai Date: Mon, 3 Jun 2024 17:30:35 -0400 Subject: [PATCH 20/20] output only on mismatch --- crates/hyperdrive-math/src/short/max.rs | 38 ++++++++++++++----------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/crates/hyperdrive-math/src/short/max.rs b/crates/hyperdrive-math/src/short/max.rs index aec4c1dc..a796e600 100644 --- a/crates/hyperdrive-math/src/short/max.rs +++ b/crates/hyperdrive-math/src/short/max.rs @@ -541,7 +541,7 @@ mod tests { if highest_rate.is_none() || fixed_rate > highest_rate.unwrap() { highest_rate = Some(fixed_rate); } - println!("Fixed rate: {}", fixed_rate); + // println!("Fixed rate: {}", fixed_rate); let checkpoint_exposure = { let value = rng.gen_range(fixed!(0)..=FixedPoint::try_from(I256::MAX)?); if rng.gen() { @@ -600,11 +600,17 @@ mod tests { Err(expected) => match actual { Err(_) => { both_fail_tests += 1; - println!("Both failed: actual: {:?} expected: {:?}", actual, expected); + // println!("Both failed: actual: {:?} expected: {:?}", actual, expected); } Ok(_) => { mismatched_tests += 1; + println!("Fixed rate: {}", fixed_rate); println!("MISMATCHED: actual: {:?} expected: {:?}", actual, expected); + + let rust_result = actual.unwrap().unwrap(); + let solidity_result = expected; + println!("Rust: {:?} Solidity: {:?}", rust_result, solidity_result); + if lowest_rate_mismatch.is_none() || fixed_rate < lowest_rate_mismatch.unwrap() { @@ -618,21 +624,21 @@ mod tests { } }, }; - let total_tests = both_pass_tests + both_fail_tests + mismatched_tests; - let failure_rate = mismatched_tests as f64 / total_tests as f64; - println!( - "Total tests: {} Both pass: {} Both fail: {} Mismatched: {} Failure rate: {}", - total_tests, both_pass_tests, both_fail_tests, mismatched_tests, failure_rate - ); - println!( - "Fuzzed over fixed rate from {:?} to {:?}", - lowest_rate, highest_rate - ); - println!( - "Mismatched fixed rate from {:?} to {:?}", - lowest_rate_mismatch, highest_rate_mismatch - ); } + let total_tests = both_pass_tests + both_fail_tests + mismatched_tests; + let failure_rate = mismatched_tests as f64 / total_tests as f64; + println!( + "Total tests: {} Both pass: {} Both fail: {} Mismatched: {} Failure rate: {}", + total_tests, both_pass_tests, both_fail_tests, mismatched_tests, failure_rate + ); + println!( + "Fuzzed over fixed rate from {:?} to {:?}", + lowest_rate, highest_rate + ); + println!( + "Mismatched fixed rate from {:?} to {:?}", + lowest_rate_mismatch, highest_rate_mismatch + ); Ok(()) }