-
Notifications
You must be signed in to change notification settings - Fork 51
Formulaic k #56
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: master
Are you sure you want to change the base?
Formulaic k #56
Changes from 55 commits
a3b67aa
ddc2153
f38424f
fb8db12
78b9e45
7b94ff3
a0b5093
c4521a3
ec97cf0
82ff781
9e0e3c4
7cd4801
e1bab51
61e362e
fbfdd91
5fe7a5f
d0fe8fe
51c792e
93fd2ca
29303c4
f8dee80
5868cc5
967da1c
a50ceb6
9b7f362
84c19ca
5ad3c1e
05cdffe
18e4790
cac6ef4
58f4891
41830cc
4138a51
7c3e11c
fa80469
8c624d4
80d1956
ed29604
665f7e0
36a288d
23636bc
d1c5327
3e48e76
5333cd4
0399928
5ead517
b76d3e7
21eeff9
aae07e6
5ee1f66
7eaeab6
eea4332
e1effd3
ff1b716
aa7d1c3
de7ab64
08da5f2
d52e6c6
f208be3
cac091a
acd64bd
478f276
466dd7f
7b6fd9b
30831d6
be98bee
e9e15e0
8a1d9d9
03b3a32
441ffbe
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 |
|---|---|---|
| @@ -1,12 +1,17 @@ | ||
| use solana_program::msg; | ||
|
|
||
| use crate::controller::repeg::apply_cost_to_market; | ||
| use crate::error::{ClearingHouseResult, ErrorCode}; | ||
| use crate::math::amm::calculate_quote_asset_amount_swapped; | ||
| use crate::math::casting::{cast, cast_to_i128}; | ||
| use crate::math::constants::PRICE_TO_PEG_PRECISION_RATIO; | ||
| use crate::math::{amm, bn, quote_asset::*}; | ||
| use crate::math::{amm, bn, quote_asset::*, repeg}; | ||
| use crate::math_error; | ||
| use crate::state::market::AMM; | ||
| use crate::state::history::curve::{ExtendedCurveHistory, ExtendedCurveRecord}; | ||
| use crate::state::market::{Market, OraclePriceData, AMM}; | ||
| use std::cell::RefMut; | ||
|
|
||
| use std::cmp::{max, min}; | ||
|
|
||
| #[derive(Clone, Copy, PartialEq)] | ||
| pub enum SwapDirection { | ||
|
|
@@ -92,6 +97,100 @@ pub fn move_price( | |
| Ok(()) | ||
| } | ||
|
|
||
| pub fn formulaic_k( | ||
| market: &mut Market, | ||
| mark_price: u128, | ||
|
||
| oracle_price_data: &OraclePriceData, | ||
| is_oracle_valid: bool, | ||
|
||
| funding_imbalance_cost: i128, | ||
| curve_history: Option<&mut RefMut<ExtendedCurveHistory>>, | ||
| now: i64, | ||
| market_index: u64, | ||
| trade_record: Option<u128>, | ||
| ) -> ClearingHouseResult { | ||
| let peg_multiplier_before = market.amm.peg_multiplier; | ||
| let base_asset_reserve_before = market.amm.base_asset_reserve; | ||
| let quote_asset_reserve_before = market.amm.quote_asset_reserve; | ||
| let sqrt_k_before = market.amm.sqrt_k; | ||
|
|
||
| // calculate budget | ||
| let budget = if funding_imbalance_cost < 0 { | ||
| // negative cost is period revenue, give back half in k increase | ||
| funding_imbalance_cost | ||
| .checked_div(2) | ||
| .ok_or_else(math_error!())? | ||
| } else if market.amm.net_revenue_since_last_funding < (funding_imbalance_cost as i64) { | ||
|
||
| // cost exceeded period revenue, take back half in k decrease | ||
| max(0, market.amm.net_revenue_since_last_funding) | ||
| .checked_sub(funding_imbalance_cost as i64) | ||
| .ok_or_else(math_error!())? | ||
| .checked_div(2) | ||
| .ok_or_else(math_error!())? as i128 | ||
| } else { | ||
| 0 | ||
| }; | ||
|
|
||
| if budget != 0 && curve_history.is_some() { | ||
| let curve_history = curve_history.unwrap(); | ||
|
|
||
| // single k scale is capped by .1% increase and .09% decrease (regardless of budget) | ||
| let (p_numer, p_denom) = amm::calculate_budgeted_k_scale(market, budget)?; | ||
|
||
|
|
||
| if p_numer > p_denom { | ||
|
||
| msg!("increase sqrt_k (* {:?}/{:?})", p_numer, p_denom); | ||
| } else if p_numer < p_denom { | ||
| msg!("decrease sqrt_k (* {:?}/{:?})", p_numer, p_denom); | ||
| } | ||
|
|
||
| let new_sqrt_k = market | ||
| .amm | ||
| .sqrt_k | ||
| .checked_mul(p_numer) | ||
| .ok_or_else(math_error!())? | ||
| .checked_div(p_denom) | ||
| .ok_or_else(math_error!())?; | ||
|
|
||
| let (adjust_k_market, adjustment_cost) = | ||
| amm::adjust_k_cost(market, bn::U256::from(new_sqrt_k))?; | ||
| let cost_applied = apply_cost_to_market(market, adjustment_cost)?; | ||
| if cost_applied { | ||
| // todo: do actual k adj here | ||
| amm::update_k(market, bn::U256::from(new_sqrt_k))?; | ||
|
|
||
| let peg_multiplier_after = market.amm.peg_multiplier; | ||
| let base_asset_reserve_after = market.amm.base_asset_reserve; | ||
| let quote_asset_reserve_after = market.amm.quote_asset_reserve; | ||
| let sqrt_k_after = market.amm.sqrt_k; | ||
|
|
||
| let record_id = curve_history.next_record_id(); | ||
| curve_history.append(ExtendedCurveRecord { | ||
| ts: now, | ||
| record_id, | ||
| market_index, | ||
| peg_multiplier_before, | ||
| base_asset_reserve_before, | ||
| quote_asset_reserve_before, | ||
| sqrt_k_before, | ||
| peg_multiplier_after, | ||
| base_asset_reserve_after, | ||
| quote_asset_reserve_after, | ||
| sqrt_k_after, | ||
| base_asset_amount_long: market.base_asset_amount_long.unsigned_abs(), | ||
| base_asset_amount_short: market.base_asset_amount_short.unsigned_abs(), | ||
| base_asset_amount: market.base_asset_amount, | ||
| open_interest: market.open_interest, | ||
| total_fee: market.amm.total_fee, | ||
| total_fee_minus_distributions: market.amm.total_fee_minus_distributions, | ||
| adjustment_cost, | ||
| oracle_price: oracle_price_data.price, | ||
| trade_record: trade_record.unwrap_or(0), | ||
| padding: [0; 5], | ||
| }); | ||
| } | ||
| } | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[allow(dead_code)] | ||
| pub fn move_to_price(amm: &mut AMM, target_price: u128) -> ClearingHouseResult { | ||
| let sqrt_k = bn::U256::from(amm.sqrt_k); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,9 @@ use std::cmp::{max, min}; | |
| use anchor_lang::prelude::*; | ||
|
|
||
| use crate::error::*; | ||
|
|
||
| use crate::controller::amm::formulaic_k; | ||
|
|
||
| use crate::math::amm; | ||
| use crate::math::amm::normalise_oracle_price; | ||
| use crate::math::casting::{cast, cast_to_i128}; | ||
|
|
@@ -14,6 +17,7 @@ use crate::math::constants::{ | |
| use crate::math::funding::{calculate_funding_payment, calculate_funding_rate_long_short}; | ||
| use crate::math::oracle; | ||
| use crate::math_error; | ||
| use crate::state::history::curve::ExtendedCurveHistory; | ||
| use crate::state::history::funding_payment::{FundingPaymentHistory, FundingPaymentRecord}; | ||
| use crate::state::history::funding_rate::{FundingRateHistory, FundingRateRecord}; | ||
| use crate::state::market::AMM; | ||
|
|
@@ -93,6 +97,7 @@ pub fn update_funding_rate( | |
| now: UnixTimestamp, | ||
| clock_slot: u64, | ||
| funding_rate_history: &mut RefMut<FundingRateHistory>, | ||
| curve_history: Option<&mut RefMut<ExtendedCurveHistory>>, | ||
| guard_rails: &OracleGuardRails, | ||
| funding_paused: bool, | ||
| precomputed_mark_price: Option<u128>, | ||
|
|
@@ -101,16 +106,21 @@ pub fn update_funding_rate( | |
| .checked_sub(market.amm.last_funding_rate_ts) | ||
| .ok_or_else(math_error!())?; | ||
|
|
||
| let mark_price = match precomputed_mark_price { | ||
| Some(mark_price) => mark_price, | ||
| None => market.amm.mark_price()?, | ||
| }; | ||
|
|
||
| // Pause funding if oracle is invalid or if mark/oracle spread is too divergent | ||
| let (block_funding_rate_update, oracle_price_data) = oracle::block_operation( | ||
| &market.amm, | ||
| price_oracle, | ||
| clock_slot, | ||
| guard_rails, | ||
| precomputed_mark_price, | ||
| Some(mark_price), | ||
| )?; | ||
| let normalised_oracle_price = | ||
| normalise_oracle_price(&market.amm, &oracle_price_data, precomputed_mark_price)?; | ||
| normalise_oracle_price(&market.amm, &oracle_price_data, Some(mark_price))?; | ||
|
|
||
| // round next update time to be available on the hour | ||
| let mut next_update_wait = market.amm.funding_period; | ||
|
|
@@ -174,6 +184,27 @@ pub fn update_funding_rate( | |
| let (funding_rate_long, funding_rate_short) = | ||
| calculate_funding_rate_long_short(market, funding_rate)?; | ||
|
|
||
| // dynamic k | ||
| let funding_imbalance_cost = funding_rate | ||
| .checked_mul(market.base_asset_amount) | ||
| .ok_or_else(math_error!())? | ||
| .checked_div( | ||
| AMM_TO_QUOTE_PRECISION_RATIO_I128 * cast_to_i128(FUNDING_PAYMENT_PRECISION)?, | ||
|
||
| ) | ||
| .ok_or_else(math_error!())?; | ||
|
|
||
| formulaic_k( | ||
| market, | ||
| mark_price, | ||
| &oracle_price_data, | ||
| true, // only way to have gotten here | ||
| funding_imbalance_cost, | ||
| curve_history, | ||
| now, | ||
| market_index, | ||
| None, | ||
| )?; | ||
|
|
||
| market.amm.cumulative_funding_rate_long = market | ||
| .amm | ||
| .cumulative_funding_rate_long | ||
|
|
||
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.
the name should be a verb/action e.g.
formulaic_update_k