Skip to content

Commit

Permalink
add get_targeted_long (#882)
Browse files Browse the repository at this point in the history
* initial commit for targeted long

* first pass at iterative approach

* update price derivative

* fix optional & required args; switch back to newton's method

* update test; adds Result on open_long; bugfix

* propagate optional bond_amount to lower fns; fixes

* bugfix and docstrings

* fix type signatures to support multiple input types

* addressing some feedback

* fixes rebase issues

* lint fixes from rebase

* addressing feedback
  • Loading branch information
dpaiton authored Apr 5, 2024
1 parent 1d12c38 commit ed2bc6d
Show file tree
Hide file tree
Showing 6 changed files with 598 additions and 23 deletions.
1 change: 1 addition & 0 deletions crates/hyperdrive-math/src/long.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ mod close;
mod fees;
mod max;
mod open;
mod targeted;
15 changes: 9 additions & 6 deletions crates/hyperdrive-math/src/long/max.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl State {
self.max_long_guess(absolute_max_base_amount, checkpoint_exposure);
let mut maybe_solvency = self.solvency_after_long(
max_base_amount,
self.calculate_open_long(max_base_amount),
self.calculate_open_long(max_base_amount).unwrap(),
checkpoint_exposure,
);
if maybe_solvency.is_none() {
Expand Down Expand Up @@ -121,7 +121,7 @@ impl State {
let possible_max_base_amount = max_base_amount + solvency / maybe_derivative.unwrap();
maybe_solvency = self.solvency_after_long(
possible_max_base_amount,
self.calculate_open_long(possible_max_base_amount),
self.calculate_open_long(possible_max_base_amount).unwrap(),
checkpoint_exposure,
);
if let Some(s) = maybe_solvency {
Expand Down Expand Up @@ -340,7 +340,7 @@ impl State {
/// It's possible that the pool is insolvent after opening a long. In this
/// case, we return `None` since the fixed point library can't represent
/// negative numbers.
fn solvency_after_long(
pub(super) fn solvency_after_long(
&self,
base_amount: FixedPoint,
bond_amount: FixedPoint,
Expand Down Expand Up @@ -380,7 +380,10 @@ impl State {
/// This derivative is negative since solvency decreases as more longs are
/// opened. We use the negation of the derivative to stay in the positive
/// domain, which allows us to use the fixed point library.
fn solvency_after_long_derivative(&self, base_amount: FixedPoint) -> Option<FixedPoint> {
pub(super) fn solvency_after_long_derivative(
&self,
base_amount: FixedPoint,
) -> Option<FixedPoint> {
let maybe_derivative = self.long_amount_derivative(base_amount);
maybe_derivative.map(|derivative| {
(derivative
Expand Down Expand Up @@ -419,7 +422,7 @@ impl State {
/// $$
/// c'(x) = \phi_{c} \cdot \left( \tfrac{1}{p} - 1 \right)
/// $$
fn long_amount_derivative(&self, base_amount: FixedPoint) -> Option<FixedPoint> {
pub(super) fn long_amount_derivative(&self, base_amount: FixedPoint) -> Option<FixedPoint> {
let share_amount = base_amount / self.vault_share_price();
let inner =
self.initial_vault_share_price() * (self.effective_share_reserves() + share_amount);
Expand Down Expand Up @@ -624,7 +627,7 @@ mod tests {
let spot_price_after_long = bob
.get_state()
.await?
.calculate_spot_price_after_long(max_long, None);
.calculate_spot_price_after_long(max_long, None)?;
bob.open_long(max_long, None, None).await?;

// One of three things should be true after opening the long:
Expand Down
31 changes: 16 additions & 15 deletions crates/hyperdrive-math/src/long/open.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use eyre::{eyre, Result};
use fixed_point::FixedPoint;

use crate::{calculate_rate_given_fixed_price, State, YieldSpace};
Expand All @@ -22,7 +23,7 @@ impl State {
/// \right) \right)^{1 - t_s}
/// \right)^{\tfrac{1}{1 - t_s}}
/// $$
pub fn calculate_open_long<F: Into<FixedPoint>>(&self, base_amount: F) -> FixedPoint {
pub fn calculate_open_long<F: Into<FixedPoint>>(&self, base_amount: F) -> Result<FixedPoint> {
let base_amount = base_amount.into();

if base_amount < self.config.minimum_transaction_amount.into() {
Expand All @@ -35,14 +36,15 @@ impl State {

// Throw an error if opening the long would result in negative interest.
let ending_spot_price =
self.calculate_spot_price_after_long(base_amount, long_amount.into());
self.calculate_spot_price_after_long(base_amount, long_amount.into())?;
let max_spot_price = self.calculate_max_spot_price();
if ending_spot_price > max_spot_price {
// TODO would be nice to return a `Result` here instead of a panic.
panic!("InsufficientLiquidity: Negative Interest");
return Err(eyre!(
"calculate_open_long: InsufficientLiquidity: Negative Interest",
));
}

long_amount - self.open_long_curve_fees(base_amount)
Ok(long_amount - self.open_long_curve_fees(base_amount))
}

/// Calculates the spot price after opening a Hyperdrive long.
Expand All @@ -51,17 +53,17 @@ impl State {
&self,
base_amount: FixedPoint,
bond_amount: Option<FixedPoint>,
) -> FixedPoint {
) -> Result<FixedPoint> {
let bond_amount = match bond_amount {
Some(bond_amount) => bond_amount,
None => self.calculate_open_long(base_amount),
None => self.calculate_open_long(base_amount)?,
};
let mut state: State = self.clone();
state.info.bond_reserves -= bond_amount.into();
state.info.share_reserves += (base_amount / state.vault_share_price()
- self.open_long_governance_fee(base_amount) / state.vault_share_price())
.into();
state.calculate_spot_price()
Ok(state.calculate_spot_price())
}

/// Calculate the spot rate after a long has been opened.
Expand All @@ -70,17 +72,16 @@ impl State {
&self,
base_amount: FixedPoint,
bond_amount: Option<FixedPoint>,
) -> FixedPoint {
calculate_rate_given_fixed_price(
self.calculate_spot_price_after_long(base_amount, bond_amount),
) -> Result<FixedPoint> {
Ok(calculate_rate_given_fixed_price(
self.calculate_spot_price_after_long(base_amount, bond_amount)?,
self.position_duration(),
)
))
}
}

#[cfg(test)]
mod tests {
use eyre::Result;
use fixed_point_macros::fixed;
use rand::{thread_rng, Rng};
use test_utils::{
Expand Down Expand Up @@ -124,7 +125,7 @@ mod tests {
let expected_spot_price = bob
.get_state()
.await?
.calculate_spot_price_after_long(base_paid, None);
.calculate_spot_price_after_long(base_paid, None)?;

// Open the long.
bob.open_long(base_paid, None, None).await?;
Expand Down Expand Up @@ -188,7 +189,7 @@ mod tests {
let expected_spot_rate = bob
.get_state()
.await?
.calculate_spot_rate_after_long(base_paid, None);
.calculate_spot_rate_after_long(base_paid, None)?;

// Open the long.
bob.open_long(base_paid, None, None).await?;
Expand Down
Loading

0 comments on commit ed2bc6d

Please sign in to comment.