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/add-unsettled-to-net-user-pnl #912

Merged
merged 14 commits into from
Apr 20, 2024
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Features
- program: admin amm summary stats update and/or reset ([#912](https://github.com/drift-labs/protocol-v2/pull/912))

### Fixes

Expand Down
30 changes: 30 additions & 0 deletions programs/drift/src/controller/amm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,3 +818,33 @@

Ok(())
}

// recalculate and update summary stats on amm which are prone too accumulating integer math errors
pub fn calculate_perp_market_amm_summary_stats(

Check warning on line 823 in programs/drift/src/controller/amm.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/amm.rs#L823

Added line #L823 was not covered by tests
perp_market: &PerpMarket,
spot_market: &SpotMarket,
perp_market_oracle_price: i64,
) -> DriftResult<i128> {
let pnl_pool_token_amount = get_token_amount(
perp_market.pnl_pool.scaled_balance,

Check warning on line 829 in programs/drift/src/controller/amm.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/amm.rs#L829

Added line #L829 was not covered by tests
spot_market,
perp_market.pnl_pool.balance_type(),

Check warning on line 831 in programs/drift/src/controller/amm.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/amm.rs#L831

Added line #L831 was not covered by tests
)?;

let fee_pool_token_amount = get_token_amount(
perp_market.amm.fee_pool.scaled_balance,

Check warning on line 835 in programs/drift/src/controller/amm.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/amm.rs#L835

Added line #L835 was not covered by tests
spot_market,
perp_market.amm.fee_pool.balance_type(),

Check warning on line 837 in programs/drift/src/controller/amm.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/amm.rs#L837

Added line #L837 was not covered by tests
)?;

let pnl_tokens_available: i128 = pnl_pool_token_amount
.safe_add(fee_pool_token_amount)?

Check warning on line 841 in programs/drift/src/controller/amm.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/amm.rs#L840-L841

Added lines #L840 - L841 were not covered by tests
.cast()?;

let net_user_pnl = amm::calculate_net_user_pnl(&perp_market.amm, perp_market_oracle_price)?;

Check warning on line 844 in programs/drift/src/controller/amm.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/amm.rs#L844

Added line #L844 was not covered by tests

// amm's mm_fee can be incorrect with drifting integer math error
let new_total_fee_minus_distributions = pnl_tokens_available.safe_sub(net_user_pnl)?;

Check warning on line 847 in programs/drift/src/controller/amm.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/amm.rs#L847

Added line #L847 was not covered by tests

Ok(new_total_fee_minus_distributions)

Check warning on line 849 in programs/drift/src/controller/amm.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/amm.rs#L849

Added line #L849 was not covered by tests
}
14 changes: 14 additions & 0 deletions programs/drift/src/controller/funding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@

market_position.last_cumulative_funding_rate = amm_cumulative_funding_rate.cast()?;
update_quote_asset_and_break_even_amount(market_position, market, market_funding_payment)?;
market.amm.net_unsettled_funding_pnl = market
.amm
.net_unsettled_funding_pnl
.safe_sub(market_funding_payment)?;

Check warning on line 85 in programs/drift/src/controller/funding.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/funding.rs#L85

Added line #L85 was not covered by tests
}

Ok(())
Expand Down Expand Up @@ -138,6 +142,10 @@
market,
market_funding_payment,
)?;
market.amm.net_unsettled_funding_pnl = market

Check warning on line 145 in programs/drift/src/controller/funding.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/funding.rs#L145

Added line #L145 was not covered by tests
.amm
.net_unsettled_funding_pnl
.safe_sub(market_funding_payment)?;

Check warning on line 148 in programs/drift/src/controller/funding.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/funding.rs#L148

Added line #L148 was not covered by tests
}
}

Expand Down Expand Up @@ -270,6 +278,12 @@
market.amm.last_funding_rate_ts,
TWENTY_FOUR_HOUR,
)?;

market.amm.net_unsettled_funding_pnl = market
.amm
.net_unsettled_funding_pnl
.safe_sub(funding_imbalance_revenue.cast()?)?;

market.amm.last_funding_rate_ts = now;

emit!(FundingRateRecord {
Expand Down
4 changes: 3 additions & 1 deletion programs/drift/src/controller/pnl/delisting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2831,7 +2831,9 @@ pub mod delisting_test {
let oracle_price_data = oracle_map.get_price_data(&market.amm.oracle).unwrap();
assert_eq!(oracle_price_data.price, 100 * PRICE_PRECISION_I64);
let net_pnl = calculate_net_user_pnl(&market.amm, oracle_price_data.price).unwrap();
assert_eq!(net_pnl, 0);
assert_eq!(net_pnl, 3449991000);
assert_eq!(market.amm.net_unsettled_funding_pnl, 3449991000); //todo?
assert_eq!(market.amm.quote_asset_amount_per_lp, 0);

drop(market);

Expand Down
19 changes: 13 additions & 6 deletions programs/drift/src/controller/position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
use crate::controller::amm::SwapDirection;
use crate::error::{DriftResult, ErrorCode};
use crate::math::casting::Cast;
use crate::math::constants::{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, QUOTE_PRECISION_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 @@ -422,10 +421,6 @@
.amm
.calculate_per_lp_delta(delta, fee_to_market, liquidity_split, base_unit)?;

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
.base_asset_amount_per_lp
Expand All @@ -446,6 +441,13 @@
market.amm.quote_asset_amount_per_lp =
market.amm.quote_asset_amount_per_lp.safe_add(per_lp_fee)?;

let lp_delta_base = market
.amm
.calculate_lp_base_delta(per_lp_delta_base, base_unit)?;

Check warning on line 446 in programs/drift/src/controller/position.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/position.rs#L446

Added line #L446 was not covered by tests
let lp_delta_quote = market
.amm
.calculate_lp_base_delta(per_lp_delta_quote, QUOTE_PRECISION_I128)?;

Check warning on line 449 in programs/drift/src/controller/position.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/position.rs#L449

Added line #L449 was not covered by tests

market.amm.base_asset_amount_with_amm = market
.amm
.base_asset_amount_with_amm
Expand All @@ -456,6 +458,11 @@
.base_asset_amount_with_unsettled_lp
.safe_add(lp_delta_base)?;

market.amm.quote_asset_amount_with_unsettled_lp = market
.amm
.quote_asset_amount_with_unsettled_lp
.safe_add(lp_delta_quote.cast()?)?;

Ok(lp_delta_base)
}

Expand Down
101 changes: 98 additions & 3 deletions programs/drift/src/instructions/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@
liquidator_fee,
if_liquidation_fee,
paused_operations: 0,
quote_spot_market_index: 0,
quote_spot_market_index: QUOTE_SPOT_MARKET_INDEX,
fee_adjustment: 0,
padding: [0; 46],
amm: AMM {
Expand Down Expand Up @@ -1002,14 +1002,91 @@
Ok(())
}

#[derive(Debug, Clone, Copy, AnchorSerialize, AnchorDeserialize, PartialEq, Eq)]
pub struct UpdatePerpMarketSummaryStatsParams {
// new aggregate unsettled user stats
pub quote_asset_amount_with_unsettled_lp: Option<i64>,
pub net_unsettled_funding_pnl: Option<i64>,
pub update_amm_summary_stats: Option<bool>,
}

#[access_control(

Check warning on line 1013 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1013

Added line #L1013 was not covered by tests
perp_market_valid(&ctx.accounts.perp_market)
valid_oracle_for_perp_market(&ctx.accounts.oracle, &ctx.accounts.perp_market)
)]
pub fn handle_update_perp_market_amm_summary_stats(

Check warning on line 1017 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1017

Added line #L1017 was not covered by tests
ctx: Context<AdminUpdatePerpMarketAmmSummaryStats>,
params: UpdatePerpMarketSummaryStatsParams,
) -> Result<()> {
let perp_market = &mut load_mut!(ctx.accounts.perp_market)?;
let spot_market = &mut load_mut!(ctx.accounts.spot_market)?;

Check warning on line 1022 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1021-L1022

Added lines #L1021 - L1022 were not covered by tests

let clock = Clock::get()?;
let price_oracle = &ctx.accounts.oracle;

Check warning on line 1025 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1024-L1025

Added lines #L1024 - L1025 were not covered by tests

let OraclePriceData {
price: oracle_price,

Check warning on line 1028 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1027-L1028

Added lines #L1027 - L1028 were not covered by tests
..
} = get_oracle_price(&perp_market.amm.oracle_source, price_oracle, clock.slot)?;

if let Some(quote_asset_amount_with_unsettled_lp) = params.quote_asset_amount_with_unsettled_lp

Check warning on line 1032 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1032

Added line #L1032 was not covered by tests
{
msg!(

Check warning on line 1034 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1034

Added line #L1034 was not covered by tests
"quote_asset_amount_with_unsettled_lp {} -> {}",
perp_market.amm.quote_asset_amount_with_unsettled_lp,

Check warning on line 1036 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1036

Added line #L1036 was not covered by tests
quote_asset_amount_with_unsettled_lp
);
perp_market.amm.quote_asset_amount_with_unsettled_lp = quote_asset_amount_with_unsettled_lp;

Check warning on line 1039 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1039

Added line #L1039 was not covered by tests
}

if let Some(net_unsettled_funding_pnl) = params.net_unsettled_funding_pnl {
msg!(

Check warning on line 1043 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1042-L1043

Added lines #L1042 - L1043 were not covered by tests
"net_unsettled_funding_pnl {} -> {}",
perp_market.amm.net_unsettled_funding_pnl,

Check warning on line 1045 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1045

Added line #L1045 was not covered by tests
net_unsettled_funding_pnl
);
perp_market.amm.net_unsettled_funding_pnl = net_unsettled_funding_pnl;

Check warning on line 1048 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1048

Added line #L1048 was not covered by tests
}

if params.update_amm_summary_stats == Some(true) {

Check warning on line 1051 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1051

Added line #L1051 was not covered by tests
let new_total_fee_minus_distributions =
controller::amm::calculate_perp_market_amm_summary_stats(
perp_market,
spot_market,

Check warning on line 1055 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1054-L1055

Added lines #L1054 - L1055 were not covered by tests
oracle_price,
)?;

msg!(

Check warning on line 1059 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1059

Added line #L1059 was not covered by tests
"updating amm summary stats for market index = {}",
perp_market.market_index,

Check warning on line 1061 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1061

Added line #L1061 was not covered by tests
);

msg!(

Check warning on line 1064 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1064

Added line #L1064 was not covered by tests
"total_fee_minus_distributions: {:?} -> {:?}",
perp_market.amm.total_fee_minus_distributions,

Check warning on line 1066 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1066

Added line #L1066 was not covered by tests
new_total_fee_minus_distributions,
);
let fee_difference = new_total_fee_minus_distributions
.safe_sub(perp_market.amm.total_fee_minus_distributions)?;

Check warning on line 1070 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1069-L1070

Added lines #L1069 - L1070 were not covered by tests

perp_market.amm.total_fee = perp_market.amm.total_fee.saturating_add(fee_difference);
perp_market.amm.total_mm_fee = perp_market.amm.total_mm_fee.saturating_add(fee_difference);
perp_market.amm.total_fee_minus_distributions = new_total_fee_minus_distributions;

Check warning on line 1074 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1072-L1074

Added lines #L1072 - L1074 were not covered by tests
}
validate_perp_market(perp_market)?;

Check warning on line 1076 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1076

Added line #L1076 was not covered by tests

Ok(())

Check warning on line 1078 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1078

Added line #L1078 was not covered by tests
}

#[access_control(
perp_market_valid(&ctx.accounts.perp_market)
)]
pub fn handle_settle_expired_market_pools_to_revenue_pool(
ctx: Context<SettleExpiredMarketPoolsToRevenuePool>,
) -> Result<()> {
let perp_market = &mut load_mut!(ctx.accounts.perp_market)?;
let spot_market = &mut load_mut!(ctx.accounts.spot_market)?;
let spot_market: &mut std::cell::RefMut<'_, SpotMarket> =

Check warning on line 1088 in programs/drift/src/instructions/admin.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/admin.rs#L1088

Added line #L1088 was not covered by tests
0xbigz marked this conversation as resolved.
Show resolved Hide resolved
&mut load_mut!(ctx.accounts.spot_market)?;
let state = &ctx.accounts.state;

let clock = Clock::get()?;
Expand Down Expand Up @@ -2819,11 +2896,29 @@
pub struct AdminUpdatePerpMarket<'info> {
pub admin: Signer<'info>,
#[account(
has_one = admin
has_one = admin
)]
pub state: Box<Account<'info, State>>,
#[account(mut)]
pub perp_market: AccountLoader<'info, PerpMarket>,
}

#[derive(Accounts)]
pub struct AdminUpdatePerpMarketAmmSummaryStats<'info> {
pub admin: Signer<'info>,
#[account(
has_one = admin
)]
pub state: Box<Account<'info, State>>,
#[account(mut)]
pub perp_market: AccountLoader<'info, PerpMarket>,
#[account(
seeds = [b"spot_market", perp_market.load()?.quote_spot_market_index.to_le_bytes().as_ref()],
bump,
)]
pub spot_market: AccountLoader<'info, SpotMarket>,
/// CHECK: checked in `admin_update_perp_market_summary_stats` ix constraint
pub oracle: AccountInfo<'info>,
}

#[derive(Accounts)]
Expand Down
2 changes: 1 addition & 1 deletion programs/drift/src/instructions/keeper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@
)?;

validate!(
quote_spot_market_index == 0,
quote_spot_market_index == QUOTE_SPOT_MARKET_INDEX,

Check warning on line 949 in programs/drift/src/instructions/keeper.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/keeper.rs#L949

Added line #L949 was not covered by tests
ErrorCode::InvalidSpotMarketAccount
)?;

Expand Down
7 changes: 7 additions & 0 deletions programs/drift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,13 @@
handle_recenter_perp_market_amm(ctx, peg_multiplier, sqrt_k)
}

pub fn update_perp_market_amm_summary_stats(

Check warning on line 699 in programs/drift/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/lib.rs#L699

Added line #L699 was not covered by tests
ctx: Context<AdminUpdatePerpMarketAmmSummaryStats>,
params: UpdatePerpMarketSummaryStatsParams,
) -> Result<()> {
handle_update_perp_market_amm_summary_stats(ctx, params)

Check warning on line 703 in programs/drift/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/lib.rs#L703

Added line #L703 was not covered by tests
}

pub fn update_perp_market_expiry(
ctx: Context<AdminUpdatePerpMarket>,
expiry_ts: i64,
Expand Down
5 changes: 4 additions & 1 deletion programs/drift/src/math/amm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,9 @@ pub fn calculate_amm_available_liquidity(
}

pub fn calculate_net_user_cost_basis(amm: &AMM) -> DriftResult<i128> {
Ok(amm.quote_asset_amount)
amm.quote_asset_amount
.safe_add(amm.quote_asset_amount_with_unsettled_lp.cast()?)?
.safe_add(amm.net_unsettled_funding_pnl.cast()?)
}

pub fn calculate_net_user_pnl(amm: &AMM, oracle_price: i64) -> DriftResult<i128> {
Expand All @@ -834,6 +836,7 @@ pub fn calculate_net_user_pnl(amm: &AMM, oracle_price: i64) -> DriftResult<i128>

let net_user_base_asset_value = amm
.base_asset_amount_with_amm
.safe_add(amm.base_asset_amount_with_unsettled_lp)?
.safe_mul(oracle_price.cast()?)?
.safe_div(PRICE_TIMES_AMM_TO_QUOTE_PRECISION_RATIO.cast()?)?;

Expand Down
Loading
Loading