-
Notifications
You must be signed in to change notification settings - Fork 200
Funding includes vamm #1971
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
base: amm-availability-update
Are you sure you want to change the base?
Funding includes vamm #1971
Changes from all commits
06b80a8
800fcc5
fd4d920
6ecb34f
0783078
b8e1214
49dad0d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2617,8 +2617,56 @@ pub fn handle_update_perp_bid_ask_twap<'c: 'info, 'info>( | |
|
|
||
| let depth = perp_market.get_market_depth_for_funding_rate()?; | ||
|
|
||
| let (bids, asks) = | ||
| let amm_worst_price_bid = perp_market | ||
| .amm | ||
| .get_price_for_swap(depth, PositionDirection::Short)?; | ||
| let amm_worst_price_ask = perp_market | ||
| .amm | ||
| .get_price_for_swap(depth, PositionDirection::Long)?; | ||
|
|
||
| let (mut bids, mut asks) = | ||
| find_bids_and_asks_from_users(perp_market, oracle_price_data, &makers, slot, now)?; | ||
| bids.retain(|level| level.price >= amm_worst_price_bid); | ||
| asks.retain(|level| level.price <= amm_worst_price_ask); | ||
|
|
||
| if !perp_market.is_operation_paused(PerpOperation::AmmFill) && !state.amm_paused()? { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. one thing i'd be worried about is if there are any weird cu issues here, should we think about a feature flag for this? |
||
| let base_per_level = depth.safe_div(10)?; | ||
| let amm_bids = | ||
| perp_market | ||
| .amm | ||
| .clone() | ||
| .get_levels(16, PositionDirection::Short, base_per_level)?; | ||
| let amm_asks = | ||
| perp_market | ||
| .amm | ||
| .clone() | ||
| .get_levels(16, PositionDirection::Long, base_per_level)?; | ||
|
|
||
| bids.extend(amm_bids); | ||
| asks.extend(amm_asks); | ||
| bids.sort_by(|a, b| b.price.cmp(&a.price)); | ||
| asks.sort_by(|a, b| a.price.cmp(&b.price)); | ||
| let merge_same_price = |side: &mut Vec<crate::math::orders::Level>| { | ||
| if side.is_empty() { | ||
| return; | ||
| } | ||
| let mut merged: Vec<crate::math::orders::Level> = Vec::with_capacity(side.len()); | ||
| for lvl in side.drain(..) { | ||
| if let Some(last) = merged.last_mut() { | ||
| if last.price == lvl.price { | ||
| last.base_asset_amount = | ||
| last.base_asset_amount.saturating_add(lvl.base_asset_amount); | ||
| continue; | ||
| } | ||
| } | ||
| merged.push(lvl); | ||
| } | ||
| *side = merged; | ||
| }; | ||
| merge_same_price(&mut bids); | ||
| merge_same_price(&mut asks); | ||
| } | ||
|
|
||
| let estimated_bid = estimate_price_from_side(&bids, depth)?; | ||
| let estimated_ask = estimate_price_from_side(&asks, depth)?; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -114,12 +114,12 @@ pub fn update_mark_twap_crank( | |
| let (amm_bid_price, amm_ask_price) = amm.bid_ask_price(amm_reserve_price)?; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: we might be able to save CUs only getting bid/ask iff on of the best bid/ask are none |
||
|
|
||
| let mut best_bid_price = match best_dlob_bid_price { | ||
| Some(best_dlob_bid_price) => best_dlob_bid_price.max(amm_bid_price), | ||
| Some(best_dlob_bid_price) => best_dlob_bid_price, | ||
| None => amm_bid_price, | ||
| }; | ||
|
|
||
| let mut best_ask_price = match best_dlob_ask_price { | ||
| Some(best_dlob_ask_price) => best_dlob_ask_price.min(amm_ask_price), | ||
| Some(best_dlob_ask_price) => best_dlob_ask_price, | ||
| None => amm_ask_price, | ||
| }; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,8 @@ | ||
| use crate::controller::amm::SwapDirection; | ||
| use crate::math::amm::{calculate_quote_asset_amount_swapped, calculate_swap_output}; | ||
| use crate::math::amm_spread::{self, get_spread_reserves}; | ||
| use crate::math::constants::PRICE_TIMES_AMM_TO_QUOTE_PRECISION_RATIO; | ||
| use crate::math::orders::{standardize_base_asset_amount, standardize_price, Level}; | ||
| use crate::state::fill_mode::FillMode; | ||
| use crate::state::pyth_lazer_oracle::PythLazerOracle; | ||
| use crate::state::user::{MarketType, Order}; | ||
|
|
@@ -1700,6 +1705,120 @@ impl AMM { | |
| self.mm_oracle_slot = mm_oracle_slot; | ||
| Ok(()) | ||
| } | ||
|
|
||
| pub fn get_levels( | ||
| &self, | ||
| levels: u8, | ||
| taker_direction: PositionDirection, | ||
| base_swap_amount_per_level: u64, | ||
| ) -> DriftResult<Vec<Level>> { | ||
| let (mut base_reserve, mut quote_reserve) = get_spread_reserves(self, taker_direction)?; | ||
|
|
||
| let (max_bids, max_asks) = amm::_calculate_market_open_bids_asks( | ||
| base_reserve, | ||
| self.min_base_asset_reserve, | ||
| self.max_base_asset_reserve, | ||
| )?; | ||
| let open_liquidity_u128: u128 = match taker_direction { | ||
| PositionDirection::Long => max_bids.unsigned_abs(), | ||
| PositionDirection::Short => max_asks.unsigned_abs(), | ||
| }; | ||
| let open_liquidity: u64 = open_liquidity_u128.min(u64::MAX as u128).cast()?; | ||
|
|
||
| if open_liquidity < self.min_order_size.saturating_mul(2) { | ||
| return Ok(Vec::new()); | ||
| } | ||
|
|
||
| let swap_dir = match taker_direction { | ||
| PositionDirection::Long => SwapDirection::Remove, | ||
| PositionDirection::Short => SwapDirection::Add, | ||
| }; | ||
|
|
||
| let mut remaining = open_liquidity; | ||
| let standardized_base_swap = | ||
| standardize_base_asset_amount(base_swap_amount_per_level, self.order_step_size)?; | ||
| if standardized_base_swap == 0 { | ||
| return Ok(Vec::new()); | ||
| } | ||
| let mut out: Vec<Level> = Vec::with_capacity(levels as usize); | ||
|
|
||
| for _ in 0..levels { | ||
| if remaining < self.order_step_size { | ||
| break; | ||
| } | ||
|
|
||
| // Sim swap | ||
| let step_swap: u64 = standardized_base_swap.min(remaining); | ||
| if step_swap == 0 { | ||
| break; | ||
| } | ||
|
|
||
| let (new_quote_reserve, new_base_reserve) = | ||
| calculate_swap_output(step_swap as u128, base_reserve, swap_dir, self.sqrt_k)?; | ||
|
|
||
| let quote_swapped = calculate_quote_asset_amount_swapped( | ||
| quote_reserve, | ||
| new_quote_reserve, | ||
| swap_dir, | ||
| self.peg_multiplier, | ||
| )?; | ||
|
|
||
| let mut price: u64 = quote_swapped | ||
| .safe_mul(PRICE_TIMES_AMM_TO_QUOTE_PRECISION_RATIO)? | ||
| .safe_div(step_swap.cast()?)? | ||
| .cast()?; | ||
|
|
||
| price = standardize_price(price, self.order_tick_size, taker_direction)?; | ||
|
|
||
| out.push(Level { | ||
| price, | ||
| base_asset_amount: step_swap, | ||
| }); | ||
|
|
||
| base_reserve = new_base_reserve; | ||
| quote_reserve = new_quote_reserve; | ||
| remaining = remaining.saturating_sub(step_swap); | ||
|
|
||
| if out.len() as u8 >= levels { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this redundant? |
||
| break; | ||
| } | ||
| } | ||
|
|
||
| Ok(out) | ||
| } | ||
|
|
||
| pub fn get_price_for_swap( | ||
| &self, | ||
| base_asset_amount: u64, | ||
| taker_direction: PositionDirection, | ||
| ) -> DriftResult<u64> { | ||
| let (base_reserve, quote_reserve) = amm_spread::get_spread_reserves(self, taker_direction)?; | ||
| let swap_direction = match taker_direction { | ||
| PositionDirection::Long => SwapDirection::Remove, | ||
| PositionDirection::Short => SwapDirection::Add, | ||
| }; | ||
|
|
||
| let (new_quote_reserve, _new_base_reserve) = calculate_swap_output( | ||
| base_asset_amount as u128, | ||
| base_reserve, | ||
| swap_direction, | ||
| self.sqrt_k, | ||
| )?; | ||
|
|
||
| let quote_swapped = calculate_quote_asset_amount_swapped( | ||
| quote_reserve, | ||
| new_quote_reserve, | ||
| swap_direction, | ||
| self.peg_multiplier, | ||
| )?; | ||
|
|
||
| let price: u64 = quote_swapped | ||
| .safe_mul(PRICE_TIMES_AMM_TO_QUOTE_PRECISION_RATIO)? | ||
| .safe_div(base_asset_amount as u128)? | ||
| .cast()?; | ||
|
|
||
| Ok(price) | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
|
|
@@ -1764,4 +1883,105 @@ impl AMM { | |
| ..AMM::default() | ||
| } | ||
| } | ||
|
|
||
| pub fn liquid_sol_test() -> Self { | ||
| AMM { | ||
| historical_oracle_data: HistoricalOracleData { | ||
| last_oracle_price: 190641285, | ||
| last_oracle_conf: 0, | ||
| last_oracle_delay: 17, | ||
| last_oracle_price_twap: 189914813, | ||
| last_oracle_price_twap_5min: 190656263, | ||
| last_oracle_price_twap_ts: 1761000653, | ||
| }, | ||
| base_asset_amount_per_lp: -213874721369, | ||
| quote_asset_amount_per_lp: -58962015125, | ||
| fee_pool: PoolBalance { | ||
| scaled_balance: 8575516773308741, | ||
| market_index: 0, | ||
| padding: [0, 0, 0, 0, 0, 0], | ||
| }, | ||
| base_asset_reserve: 24302266099492168, | ||
| quote_asset_reserve: 24291832241447530, | ||
| concentration_coef: 1004142, | ||
| min_base_asset_reserve: 24196060267862680, | ||
| max_base_asset_reserve: 24396915542699764, | ||
| sqrt_k: 24297048610394662, | ||
| peg_multiplier: 190724934, | ||
| terminal_quote_asset_reserve: 24297816895589961, | ||
| base_asset_amount_long: 917177880000000, | ||
| base_asset_amount_short: -923163630000000, | ||
| base_asset_amount_with_amm: -5985750000000, | ||
| base_asset_amount_with_unsettled_lp: 0, | ||
| max_open_interest: 2000000000000000, | ||
| quote_asset_amount: 15073495357350, | ||
| quote_entry_amount_long: -182456763836058, | ||
| quote_entry_amount_short: 182214483467437, | ||
| quote_break_even_amount_long: -181616323258115, | ||
| quote_break_even_amount_short: 180666910938502, | ||
| user_lp_shares: 0, | ||
| last_funding_rate: 142083, | ||
| last_funding_rate_long: 142083, | ||
| last_funding_rate_short: 142083, | ||
| last_24h_avg_funding_rate: -832430, | ||
| total_fee: 23504910735696, | ||
| total_mm_fee: 8412188362643, | ||
| total_exchange_fee: 15240376207986, | ||
| total_fee_minus_distributions: 12622783464171, | ||
| total_fee_withdrawn: 7622904850984, | ||
| total_liquidation_fee: 5153159954719, | ||
| cumulative_funding_rate_long: 48574028958, | ||
| cumulative_funding_rate_short: 48367829283, | ||
| total_social_loss: 4512659649, | ||
| ask_base_asset_reserve: 24307711375337898, | ||
| ask_quote_asset_reserve: 24286390522755450, | ||
| bid_base_asset_reserve: 24318446036975185, | ||
| bid_quote_asset_reserve: 24275670011080633, | ||
| last_oracle_normalised_price: 190641285, | ||
| last_oracle_reserve_price_spread_pct: 0, | ||
| last_bid_price_twap: 189801870, | ||
| last_ask_price_twap: 189877406, | ||
| last_mark_price_twap: 189839638, | ||
| last_mark_price_twap_5min: 190527180, | ||
| last_update_slot: 374711191, | ||
| last_oracle_conf_pct: 491, | ||
| net_revenue_since_last_funding: 9384752152, | ||
| last_funding_rate_ts: 1760997616, | ||
| funding_period: 3600, | ||
| order_step_size: 10000000, | ||
| order_tick_size: 100, | ||
| min_order_size: 10000000, | ||
| mm_oracle_slot: 374711192, | ||
| volume_24h: 114093279361263, | ||
| long_intensity_volume: 1572903262040, | ||
| short_intensity_volume: 3352472398103, | ||
| last_trade_ts: 1761000641, | ||
| mark_std: 623142, | ||
| oracle_std: 727888, | ||
| last_mark_price_twap_ts: 1761000646, | ||
| base_spread: 100, | ||
| max_spread: 20000, | ||
| long_spread: 40, | ||
| short_spread: 842, | ||
| mm_oracle_price: 190643458, | ||
| max_fill_reserve_fraction: 25000, | ||
| max_slippage_ratio: 50, | ||
| curve_update_intensity: 110, | ||
| amm_jit_intensity: 100, | ||
| last_oracle_valid: true, | ||
| target_base_asset_amount_per_lp: -565000000, | ||
| per_lp_base: 3, | ||
| taker_speed_bump_override: 5, | ||
| amm_spread_adjustment: -20, | ||
| oracle_slot_delay_override: -1, | ||
| mm_oracle_sequence_id: 1761000654650000, | ||
| net_unsettled_funding_pnl: 1042875, | ||
| quote_asset_amount_with_unsettled_lp: -112671203108, | ||
| reference_price_offset: -488, | ||
| amm_inventory_spread_adjustment: -20, | ||
| last_funding_oracle_twap: 189516656, | ||
| reference_price_offset_deadband_pct: 10, | ||
| ..AMM::default() | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
technically this is average price, does that mess with things?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can get the worst case price by looking at base/quote reserves to get price of amm at end of swap