Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions 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: allow limit orders without auctions in swift ([#1661](https://github.com/drift-labs/protocol-v2/pull/1661))
- program: add taker_speed_bump_override and amm_spread_adjustment ([#1665](https://github.com/drift-labs/protocol-v2/pull/1665))

### Fixes

Expand Down
42 changes: 39 additions & 3 deletions programs/drift/src/controller/amm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use crate::math::amm::calculate_quote_asset_amount_swapped;
use crate::math::amm_spread::{calculate_spread_reserves, get_spread_reserves};
use crate::math::casting::Cast;
use crate::math::constants::{
CONCENTRATION_PRECISION, FEE_POOL_TO_REVENUE_POOL_THRESHOLD, K_BPS_UPDATE_SCALE,
MAX_CONCENTRATION_COEFFICIENT, MAX_K_BPS_INCREASE, MAX_SQRT_K,
CONCENTRATION_PRECISION, FEE_ADJUSTMENT_MAX, FEE_POOL_TO_REVENUE_POOL_THRESHOLD,
K_BPS_UPDATE_SCALE, MAX_CONCENTRATION_COEFFICIENT, MAX_K_BPS_INCREASE, MAX_SQRT_K,
};
use crate::math::cp_curve::get_update_k_result;
use crate::math::repeg::get_total_fee_lower_bound;
Expand Down Expand Up @@ -209,7 +209,7 @@ pub fn update_spreads(market: &mut PerpMarket, reserve_price: u64) -> DriftResul
0
};

let (long_spread, short_spread) = if market.amm.curve_update_intensity > 0 {
let (mut long_spread, mut short_spread) = if market.amm.curve_update_intensity > 0 {
amm_spread::calculate_spread(
market.amm.base_spread,
market.amm.last_oracle_reserve_price_spread_pct,
Expand All @@ -236,6 +236,42 @@ pub fn update_spreads(market: &mut PerpMarket, reserve_price: u64) -> DriftResul
(half_base_spread, half_base_spread)
};

if market.amm.amm_spread_adjustment < 0 {
long_spread = long_spread
.saturating_sub(
long_spread
.safe_mul(market.amm.amm_spread_adjustment.unsigned_abs().cast()?)
.unwrap_or(u32::MAX)
.safe_div(100)?,
)
.max(1);
short_spread = short_spread
.saturating_sub(
short_spread
.safe_mul(market.amm.amm_spread_adjustment.unsigned_abs().cast()?)
.unwrap_or(u32::MAX)
.safe_div(100)?,
)
.max(1);
} else if market.amm.amm_spread_adjustment > 0 {
long_spread = long_spread
.saturating_add(
long_spread
.safe_mul(market.amm.amm_spread_adjustment.cast()?)
.unwrap_or(u32::MAX)
.safe_div_ceil(100)?,
)
.max(1);
short_spread = short_spread
.saturating_add(
short_spread
.safe_mul(market.amm.amm_spread_adjustment.cast()?)
.unwrap_or(u32::MAX)
.safe_div_ceil(100)?,
)
.max(1);
}

market.amm.long_spread = long_spread;
market.amm.short_spread = short_spread;
market.amm.reference_price_offset = reference_price_offset;
Expand Down
6 changes: 5 additions & 1 deletion programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,7 @@ pub fn fill_perp_order(
let amm_lp_allowed_to_jit_make: bool;
let oracle_valid_for_amm_fill: bool;
let oracle_stale_for_margin: bool;
let min_auction_duration: u8;
let mut amm_is_available = !state.amm_paused()?;
{
let market = &mut perp_market_map.get_ref_mut(&market_index)?;
Expand Down Expand Up @@ -1113,6 +1114,9 @@ pub fn fill_perp_order(
.last_oracle_price_twap_5min;
oracle_validity = _oracle_validity;
perp_market_index = market.market_index;

min_auction_duration =
market.get_min_perp_auction_duration(state.min_perp_auction_duration);
}

// allow oracle price to be used to calculate limit price if it's valid or stale for amm
Expand Down Expand Up @@ -1288,7 +1292,7 @@ pub fn fill_perp_order(
valid_oracle_price,
now,
slot,
state.min_perp_auction_duration,
min_auction_duration,
amm_availability,
fill_mode,
oracle_stale_for_margin,
Expand Down
47 changes: 44 additions & 3 deletions programs/drift/src/instructions/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,7 +1041,8 @@ pub fn handle_initialize_perp_market(
target_base_asset_amount_per_lp: 0,
per_lp_base: 0,
padding1: 0,
padding2: 0,
taker_speed_bump_override: 0,
amm_spread_adjustment: 0,
total_fee_earned_per_lp: 0,
net_unsettled_funding_pnl: 0,
quote_asset_amount_with_unsettled_lp: 0,
Expand Down Expand Up @@ -3910,7 +3911,7 @@ pub fn handle_update_perp_market_number_of_users(
}

pub fn handle_update_perp_market_fuel(
ctx: Context<AdminUpdatePerpMarketFuel>,
ctx: Context<HotAdminUpdatePerpMarket>,
fuel_boost_taker: Option<u8>,
fuel_boost_maker: Option<u8>,
fuel_boost_position: Option<u8>,
Expand Down Expand Up @@ -3987,6 +3988,46 @@ pub fn handle_update_perp_market_protected_maker_params(
Ok(())
}

#[access_control(
perp_market_valid(&ctx.accounts.perp_market)
)]
pub fn handle_update_perp_market_taker_speed_bump_override(
ctx: Context<HotAdminUpdatePerpMarket>,
taker_speed_bump_override: i8,
) -> Result<()> {
let perp_market = &mut load_mut!(ctx.accounts.perp_market)?;
msg!("perp market {}", perp_market.market_index);

msg!(
"perp_market.amm.taker_speed_bump_override: {:?} -> {:?}",
perp_market.amm.taker_speed_bump_override,
taker_speed_bump_override
);

perp_market.amm.taker_speed_bump_override = taker_speed_bump_override;
Ok(())
}

#[access_control(
perp_market_valid(&ctx.accounts.perp_market)
)]
pub fn handle_update_perp_market_amm_spread_adjustment(
ctx: Context<HotAdminUpdatePerpMarket>,
amm_spread_adjustment: i8,
) -> Result<()> {
let perp_market = &mut load_mut!(ctx.accounts.perp_market)?;
msg!("perp market {}", perp_market.market_index);

msg!(
"perp_market.amm.amm_spread_adjustment: {:?} -> {:?}",
perp_market.amm.amm_spread_adjustment,
amm_spread_adjustment
);

perp_market.amm.amm_spread_adjustment = amm_spread_adjustment;
Ok(())
}

#[access_control(
spot_market_valid(&ctx.accounts.spot_market)
)]
Expand Down Expand Up @@ -4865,7 +4906,7 @@ pub struct AdminUpdatePerpMarket<'info> {
}

#[derive(Accounts)]
pub struct AdminUpdatePerpMarketFuel<'info> {
pub struct HotAdminUpdatePerpMarket<'info> {
#[account(
constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin
)]
Expand Down
16 changes: 15 additions & 1 deletion programs/drift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1513,7 +1513,7 @@ pub mod drift {
}

pub fn update_perp_market_fuel(
ctx: Context<AdminUpdatePerpMarketFuel>,
ctx: Context<HotAdminUpdatePerpMarket>,
fuel_boost_taker: Option<u8>,
fuel_boost_maker: Option<u8>,
fuel_boost_position: Option<u8>,
Expand All @@ -1533,6 +1533,20 @@ pub mod drift {
)
}

pub fn update_perp_market_taker_speed_bump_override(
ctx: Context<HotAdminUpdatePerpMarket>,
taker_speed_bump_override: i8,
) -> Result<()> {
handle_update_perp_market_taker_speed_bump_override(ctx, taker_speed_bump_override)
}

pub fn update_perp_market_amm_spread_adjustment(
ctx: Context<HotAdminUpdatePerpMarket>,
amm_spread_adjustment: i8,
) -> Result<()> {
handle_update_perp_market_amm_spread_adjustment(ctx, amm_spread_adjustment)
}

pub fn update_spot_market_fuel(
ctx: Context<AdminUpdateSpotMarketFuel>,
fuel_boost_deposits: Option<u8>,
Expand Down
58 changes: 58 additions & 0 deletions programs/drift/src/math/cp_curve/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,64 @@ fn calculate_k_tests_wrapper_fcn() {
assert_eq!(pct_change_in_k, 10007); // k was increased .07%
}

#[test]
fn amm_spread_adj_logic() {
let mut market = PerpMarket {
amm: AMM {
base_asset_reserve: 100 * AMM_RESERVE_PRECISION,
quote_asset_reserve: 100 * AMM_RESERVE_PRECISION,
terminal_quote_asset_reserve: 999900009999000 * AMM_RESERVE_PRECISION,
sqrt_k: 100 * AMM_RESERVE_PRECISION,
peg_multiplier: 50_000_000_000,
base_asset_amount_with_amm: (AMM_RESERVE_PRECISION / 10) as i128,
base_asset_amount_long: (AMM_RESERVE_PRECISION / 10) as i128,
order_step_size: 5,
base_spread: 100,
max_spread: 10000,
..AMM::default_test()
},
margin_ratio_initial: 1000,
..PerpMarket::default()
};
// let (t_price, _t_qar, _t_bar) = calculate_terminal_price_and_reserves(&market.amm).unwrap();
// market.amm.terminal_quote_asset_reserve = _t_qar;

let mut position = PerpPosition {
..PerpPosition::default()
};

mint_lp_shares(&mut position, &mut market, BASE_PRECISION_U64).unwrap();

market.amm.base_asset_amount_per_lp = 1;
market.amm.quote_asset_amount_per_lp = -QUOTE_PRECISION_I64 as i128;

let reserve_price = market.amm.reserve_price().unwrap();
update_spreads(&mut market, reserve_price).unwrap();

assert_eq!(market.amm.long_spread, 50);
assert_eq!(market.amm.short_spread, 50);

market.amm.amm_spread_adjustment = -100;
update_spreads(&mut market, reserve_price).unwrap();
assert_eq!(market.amm.long_spread, 1);
assert_eq!(market.amm.short_spread, 1);

market.amm.amm_spread_adjustment = 100;
update_spreads(&mut market, reserve_price).unwrap();
assert_eq!(market.amm.long_spread, 100);
assert_eq!(market.amm.short_spread, 100);

market.amm.amm_spread_adjustment = 20;
update_spreads(&mut market, reserve_price).unwrap();
assert_eq!(market.amm.long_spread, 60);
assert_eq!(market.amm.short_spread, 60);

market.amm.amm_spread_adjustment = 120;
update_spreads(&mut market, reserve_price).unwrap();
assert_eq!(market.amm.long_spread, 110);
assert_eq!(market.amm.short_spread, 110);
}

#[test]
fn calculate_k_with_lps_tests() {
let mut market = PerpMarket {
Expand Down
1 change: 0 additions & 1 deletion programs/drift/src/math/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use crate::math::casting::Cast;
use crate::state::fill_mode::FillMode;
use crate::state::protected_maker_mode_config::ProtectedMakerParams;
use crate::state::user::OrderBitFlag;
use crate::BASE_PRECISION_U64;
use crate::{
load, math, FeeTier, State, BASE_PRECISION_I128, FEE_ADJUSTMENT_MAX,
MAX_PREDICTION_MARKET_PRICE, MAX_PREDICTION_MARKET_PRICE_I64, OPEN_ORDER_MARGIN_REQUIREMENT,
Expand Down
17 changes: 15 additions & 2 deletions programs/drift/src/state/perp_market.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,14 @@ impl PerpMarket {
tick_size: self.amm.order_tick_size,
}
}

pub fn get_min_perp_auction_duration(&self, default_min_auction_duration: u8) -> u8 {
if self.amm.taker_speed_bump_override != 0 {
self.amm.taker_speed_bump_override.max(0).unsigned_abs()
} else {
default_min_auction_duration
}
}
}

#[cfg(test)]
Expand Down Expand Up @@ -1034,8 +1042,12 @@ pub struct AMM {
pub target_base_asset_amount_per_lp: i32,
/// expo for unit of per_lp, base 10 (if per_lp_base=X, then per_lp unit is 10^X)
pub per_lp_base: i8,
/// the override for the state.min_perp_auction_duration
/// 0 is no override, -1 is disable speed bump, 1-100 is literal speed bump
pub taker_speed_bump_override: i8,
/// signed scale amm_spread similar to fee_adjustment logic (-100 = 0, 100 = double)
pub amm_spread_adjustment: i8,
pub padding1: u8,
pub padding2: u16,
pub total_fee_earned_per_lp: u64,
pub net_unsettled_funding_pnl: i64,
pub quote_asset_amount_with_unsettled_lp: i64,
Expand Down Expand Up @@ -1123,8 +1135,9 @@ impl Default for AMM {
last_oracle_valid: false,
target_base_asset_amount_per_lp: 0,
per_lp_base: 0,
taker_speed_bump_override: 0,
amm_spread_adjustment: 0,
padding1: 0,
padding2: 0,
total_fee_earned_per_lp: 0,
net_unsettled_funding_pnl: 0,
quote_asset_amount_with_unsettled_lp: 0,
Expand Down
55 changes: 55 additions & 0 deletions programs/drift/src/state/perp_market/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,58 @@ mod get_margin_ratio {
assert_eq!(margin_ratio_maintenance, MARGIN_PRECISION / 100);
}
}

mod get_min_perp_auction_duration {
use crate::state::perp_market::{PerpMarket, AMM};
use crate::State;

#[test]
fn test_get_speed_bump() {
let perp_market = PerpMarket {
amm: AMM {
taker_speed_bump_override: 0,
..AMM::default()
},
..PerpMarket::default()
};

let state = State {
min_perp_auction_duration: 10,
..State::default()
};

// no override uses state value
assert_eq!(
perp_market.get_min_perp_auction_duration(state.min_perp_auction_duration),
10
);

let perp_market = PerpMarket {
amm: AMM {
taker_speed_bump_override: -1,
..AMM::default()
},
..PerpMarket::default()
};

// -1 override disables speed bump
assert_eq!(
perp_market.get_min_perp_auction_duration(state.min_perp_auction_duration),
0
);

let perp_market = PerpMarket {
amm: AMM {
taker_speed_bump_override: 20,
..AMM::default()
},
..PerpMarket::default()
};

// positive override uses override value
assert_eq!(
perp_market.get_min_perp_auction_duration(state.min_perp_auction_duration),
20
);
}
}
Loading
Loading