Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bigz/lp shares rebase #568

Merged
merged 33 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
700834b
start test
crispheaney Aug 4, 2023
6095201
improve lp_delta_quote
0xbigz Aug 4, 2023
21938cf
improve per_lp_delta_quote
0xbigz Aug 4, 2023
a612655
init per_lp_base
0xbigz Aug 5, 2023
dccb7e4
add rebase functions (wip)
0xbigz Aug 7, 2023
552a030
rm err msg
0xbigz Aug 8, 2023
a9c46ba
add controller rebase to proper locations
0xbigz Aug 8, 2023
2cc07d8
Merge branch 'master' into bigz/lp-shares-rebase
0xbigz Aug 10, 2023
16d8201
add rebase cargo test
0xbigz Aug 10, 2023
49d52b4
(wip) k out of wack
0xbigz Aug 10, 2023
08fb72c
fix rebase test and add more asserts
0xbigz Aug 12, 2023
da0b452
format fix
0xbigz Aug 13, 2023
9a54ad1
incorp basic example to typescript tests
0xbigz Aug 14, 2023
fc13b15
fix rebase math in position.rs (wip)
0xbigz Aug 14, 2023
5168d9a
wip continue
0xbigz Aug 15, 2023
98a267f
working baseAssetAmountWithUnsettledLp
0xbigz Aug 15, 2023
55e4292
mvp encapsulation of update_lp_market_position
0xbigz Aug 15, 2023
f463039
src/user.ts: add perLpBase to empty position
0xbigz Aug 15, 2023
184db15
remove logs
0xbigz Aug 15, 2023
d4f64ef
simplify base unit logic more
0xbigz Aug 15, 2023
63e2294
add get_per_lp_base_unit
0xbigz Aug 15, 2023
53525d4
simplify per_lp_fee and add numbers to test
0xbigz Aug 16, 2023
e57d4f7
properly set per_lp_base for lp_share=0 in mint_lp_shares (and add sd…
0xbigz Aug 16, 2023
76174c4
incorp feedback / format
0xbigz Aug 16, 2023
b15592c
tests/liquidityProvider.ts: work with sdk change
0xbigz Aug 16, 2023
7b8f333
Merge branch 'master' into bigz/lp-shares-rebase
0xbigz Aug 16, 2023
68fe390
admin.rs: add constraint on per_lp_base range
0xbigz Aug 16, 2023
1a8475d
Merge branch 'master' into bigz/lp-shares-rebase
0xbigz Aug 21, 2023
51df36c
add apply_lp_rebase_to_perp_position to simulate_settled_lp_position
0xbigz Aug 21, 2023
bfbbc2f
use get_per_lp_base_unit consistently (wip sdk test for negative lp b…
0xbigz Aug 21, 2023
6d32299
cut excess return values in calculate_lp_delta
0xbigz Aug 21, 2023
0dc1f29
fix getPerpPositionWithLPSettle with negative perLpBase delta
0xbigz Aug 22, 2023
569376e
remove all self from simulate_settled_lp_position
0xbigz Aug 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Features

- program: add reduce only user status ([#560](https://github.com/drift-labs/protocol-v2/pull/560))
- program: add per_lp_base on market/position ([#568](https://github.com/drift-labs/protocol-v2/pull/568))

### Fixes

Expand All @@ -24,7 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- program: add deposit_into_spot_market_revenue_pool ([#520](https://github.com/drift-labs/protocol-v2/pull/520))
- program: make users w excessive withdraws pay fees ([#547](https://github.com/drift-labs/protocol-v2/pull/547))
- program: allow settle pnl and spot fills via match when utilization is 100% ([#525](https://github.com/drift-labs/protocol-v2/pull/525))
- program: allow settle pnl and spot fills via match when utilization is 100% ([#525](https://github.com/drift-labs/protocol-v2/pull/525))
- program: new update_perp_bid_ask_twap ix ([#548](https://github.com/drift-labs/protocol-v2/pull/548))
- program: dont check price bands for place order ([#556](https://github.com/drift-labs/protocol-v2/pull/556))

Expand Down
108 changes: 107 additions & 1 deletion programs/drift/src/controller/lp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,108 @@ use anchor_lang::prelude::Account;
#[cfg(test)]
mod tests;

pub fn apply_lp_rebase_to_perp_market(
perp_market: &mut PerpMarket,
expo_diff: i8,
) -> DriftResult<()> {
// target_base_asset_amount_per_lp is the only one that it doesnt get applied
// thus changing the base of lp and without changing target_base_asset_amount_per_lp
// causes an implied change

validate!(expo_diff != 0, ErrorCode::DefaultError, "expo_diff = 0")?;

perp_market.amm.per_lp_base = perp_market.amm.per_lp_base.safe_add(expo_diff)?;
let rebase_divisor: i128 = 10_i128.pow(expo_diff.abs().cast()?);

if expo_diff > 0 {
perp_market.amm.base_asset_amount_per_lp = perp_market
.amm
.base_asset_amount_per_lp
.safe_mul(rebase_divisor)?;

perp_market.amm.quote_asset_amount_per_lp = perp_market
.amm
.quote_asset_amount_per_lp
.safe_mul(rebase_divisor)?;

perp_market.amm.total_fee_earned_per_lp = perp_market
.amm
.total_fee_earned_per_lp
.safe_mul(rebase_divisor.cast()?)?;
} else {
perp_market.amm.base_asset_amount_per_lp = perp_market
.amm
.base_asset_amount_per_lp
.safe_div(rebase_divisor)?;

perp_market.amm.quote_asset_amount_per_lp = perp_market
.amm
.quote_asset_amount_per_lp
.safe_div(rebase_divisor)?;

perp_market.amm.total_fee_earned_per_lp = perp_market
.amm
.total_fee_earned_per_lp
.safe_div(rebase_divisor.cast()?)?;
}

msg!(
"rebasing perp market_index={} per_lp_base expo_diff={}",
perp_market.market_index,
expo_diff,
);

crate::validation::perp_market::validate_perp_market(perp_market)?;

Ok(())
}

pub fn apply_lp_rebase_to_perp_position(
perp_market: &PerpMarket,
perp_position: &mut PerpPosition,
) -> DriftResult<()> {
let expo_diff = perp_market
.amm
.per_lp_base
.safe_sub(perp_position.per_lp_base)?;

if expo_diff > 0 {
let rebase_divisor: i64 = 10_i64.pow(expo_diff.cast()?);

perp_position.last_base_asset_amount_per_lp = perp_position
.last_base_asset_amount_per_lp
.safe_mul(rebase_divisor)?;
perp_position.last_quote_asset_amount_per_lp = perp_position
.last_quote_asset_amount_per_lp
.safe_mul(rebase_divisor)?;

msg!(
"rebasing perp position for market_index={} per_lp_base by expo_diff={}",
perp_market.market_index,
expo_diff,
);
} else if expo_diff < 0 {
let rebase_divisor: i64 = 10_i64.pow(expo_diff.abs().cast()?);

perp_position.last_base_asset_amount_per_lp = perp_position
.last_base_asset_amount_per_lp
.safe_div(rebase_divisor)?;
perp_position.last_quote_asset_amount_per_lp = perp_position
.last_quote_asset_amount_per_lp
.safe_div(rebase_divisor)?;

msg!(
"rebasing perp position for market_index={} per_lp_base by expo_diff={}",
perp_market.market_index,
expo_diff,
);
}

perp_position.per_lp_base = perp_position.per_lp_base.safe_add(expo_diff)?;

Ok(())
}

pub fn mint_lp_shares(
0xbigz marked this conversation as resolved.
Show resolved Hide resolved
position: &mut PerpPosition,
market: &mut PerpMarket,
Expand All @@ -40,6 +142,7 @@ pub fn mint_lp_shares(
} else {
position.last_base_asset_amount_per_lp = amm.base_asset_amount_per_lp.cast()?;
position.last_quote_asset_amount_per_lp = amm.quote_asset_amount_per_lp.cast()?;
position.per_lp_base = amm.per_lp_base;
}

// add share balance
Expand Down Expand Up @@ -78,6 +181,8 @@ pub fn settle_lp_position(
)?;
}

apply_lp_rebase_to_perp_position(market, position)?;

let mut lp_metrics: crate::math::lp::LPMetrics =
calculate_settle_lp_metrics(&market.amm, position)?;

Expand Down Expand Up @@ -184,9 +289,10 @@ pub fn burn_lp_shares(
crate::validate!(
unsettled_remainder.unsigned_abs() <= market.amm.order_step_size as u128,
ErrorCode::UnableToBurnLPTokens,
"unsettled baa on final burn too big rel to stepsize {}: {}",
"unsettled baa on final burn too big rel to stepsize {}: {} (remainder:{})",
market.amm.order_step_size,
market.amm.base_asset_amount_with_unsettled_lp,
position.remainder_base_asset_amount
)?;

// sub bc lps take the opposite side of the user
Expand Down
4 changes: 3 additions & 1 deletion programs/drift/src/controller/lp/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,8 @@ fn test_lp_margin_calc() {
market.amm.cumulative_funding_rate_long *= 2;
market.amm.cumulative_funding_rate_short *= 2;

apply_lp_rebase_to_perp_market(&mut market, 1).unwrap();

let sim_user_pos = user.perp_positions[0]
.simulate_settled_lp_position(&market, oracle_price_data.price)
.unwrap();
Expand All @@ -718,7 +720,7 @@ fn test_lp_margin_calc() {
);
assert_eq!(sim_user_pos.base_asset_amount, 101000000000);
assert_eq!(sim_user_pos.quote_asset_amount, -20000000000);
assert_eq!(sim_user_pos.last_cumulative_funding_rate, 0);
assert_eq!(sim_user_pos.last_cumulative_funding_rate, 16900000000);

// ensure margin calc doesnt incorrectly count funding rate (funding pnl MUST come before settling lp)
let (margin_requirement, weighted_unrealized_pnl, worse_case_base_asset_value) =
Expand Down
70 changes: 14 additions & 56 deletions programs/drift/src/controller/position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ use crate::controller;
use crate::controller::amm::SwapDirection;
use crate::error::{DriftResult, ErrorCode};
use crate::math::casting::Cast;
use crate::math::constants::{
AMM_RESERVE_PRECISION, AMM_RESERVE_PRECISION_I128, LP_FEE_SLICE_DENOMINATOR,
LP_FEE_SLICE_NUMERATOR, MAX_BASE_ASSET_AMOUNT_WITH_AMM, PERP_DECIMALS,
};
use crate::math::helpers::get_proportion_i128;
use crate::math::constants::{MAX_BASE_ASSET_AMOUNT_WITH_AMM, PERP_DECIMALS};
// use crate::math::helpers::get_proportion_i128;
use crate::math::orders::{
calculate_quote_asset_amount_for_maker_order, get_position_delta_for_fill,
is_multiple_of_step_size,
Expand Down Expand Up @@ -383,42 +380,21 @@ pub fn update_lp_market_position(
delta: &PositionDelta,
fee_to_market: i128,
liquidity_split: AMMLiquiditySplit,
) -> DriftResult<(i128, i128, i128)> {
let user_lp_shares = market.amm.user_lp_shares;

if user_lp_shares == 0 || liquidity_split == AMMLiquiditySplit::ProtocolOwned {
return Ok((0, 0, 0)); // no need to split with LP
) -> DriftResult<i128> {
if market.amm.user_lp_shares == 0 || liquidity_split == AMMLiquiditySplit::ProtocolOwned {
return Ok(0); // no need to split with LP
}

let total_lp_shares = if liquidity_split == AMMLiquiditySplit::LPOwned {
market.amm.user_lp_shares
} else {
market.amm.sqrt_k
};

// update Market per lp position
let per_lp_delta_base = get_proportion_i128(
delta.base_asset_amount.cast()?,
AMM_RESERVE_PRECISION,
total_lp_shares,
)?;
let base_unit: i128 = market.amm.get_per_lp_base_unit()?;

let mut per_lp_delta_quote = get_proportion_i128(
delta.quote_asset_amount.cast()?,
AMM_RESERVE_PRECISION,
total_lp_shares,
)?;
let (per_lp_delta_base, per_lp_delta_quote, per_lp_fee) =
market
.amm
.calculate_per_lp_delta(delta, fee_to_market, liquidity_split, base_unit)?;

// user position delta is short => lp position delta is long
if per_lp_delta_base < 0 {
// add one => lp subtract 1
per_lp_delta_quote = per_lp_delta_quote.safe_add(1)?;
}

let lp_delta_base =
get_proportion_i128(per_lp_delta_base, user_lp_shares, AMM_RESERVE_PRECISION)?;
let lp_delta_quote =
get_proportion_i128(per_lp_delta_quote, user_lp_shares, AMM_RESERVE_PRECISION)?;
let lp_delta_base = market
.amm
.calculate_lp_base_delta(per_lp_delta_base, base_unit)?;

market.amm.base_asset_amount_per_lp = market
.amm
Expand All @@ -430,24 +406,6 @@ pub fn update_lp_market_position(
.quote_asset_amount_per_lp
.safe_add(-per_lp_delta_quote)?;

// 1/5 of fee auto goes to market
// the rest goes to lps/market proportional
let lp_fee = get_proportion_i128(
fee_to_market,
LP_FEE_SLICE_NUMERATOR,
LP_FEE_SLICE_DENOMINATOR,
)?
.safe_mul(user_lp_shares.cast::<i128>()?)?
.safe_div(total_lp_shares.cast::<i128>()?)?;

let per_lp_fee: i128 = if lp_fee > 0 {
lp_fee
.safe_mul(AMM_RESERVE_PRECISION_I128)?
.safe_div(user_lp_shares.cast::<i128>()?)?
} else {
0
};

// track total fee earned by lps (to attribute breakdown of IL)
market.amm.total_fee_earned_per_lp = market
.amm
Expand All @@ -468,7 +426,7 @@ pub fn update_lp_market_position(
.base_asset_amount_with_unsettled_lp
.safe_add(lp_delta_base)?;

Ok((lp_delta_base, lp_delta_quote, lp_fee))
Ok(lp_delta_base)
}

pub fn update_position_with_base_asset_amount(
Expand Down
Loading