Skip to content
Open
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
a3b67aa
capped funding: fix bug when total fee lb is above total_fee_minus_di…
Jan 14, 2022
ddc2153
repeg: total_fee_lb helper function
Jan 14, 2022
f38424f
repeg: add formulaic/non-error throwing controller function
Jan 14, 2022
fb8db12
formulaic repeg init
Jan 16, 2022
78b9e45
formula repeg: cargo fmt
Jan 16, 2022
7b94ff3
form-repeg: use mark price precomputed
Jan 18, 2022
a0b5093
clearing_house: calculate_peg_from_target_price, do repeg when profit…
Jan 20, 2022
c4521a3
merge master
Jan 20, 2022
ec97cf0
Merge remote-tracking branch 'origin/master' into bigz/formualic-repeg
Jan 30, 2022
82ff781
merge etc
0xbigz Feb 18, 2022
9e0e3c4
merge orders
0xbigz Feb 28, 2022
7cd4801
retryTxSender: init
crispheaney Feb 27, 2022
e1bab51
sdk: Added logic to update provider for tx sender when updating walle…
lukecaan Feb 28, 2022
61e362e
clearing_house: update oracle guard rails
crispheaney Feb 28, 2022
fbfdd91
sdk: add bulkUserSubscription to index.ts
crispheaney Mar 1, 2022
5fe7a5f
clearing_house: handle trigger market orders filling more than order …
crispheaney Mar 2, 2022
d0fe8fe
Revert "clearing_house: handle trigger market orders filling more tha…
crispheaney Mar 2, 2022
51c792e
clearing_house: calculate_base_asset_amount_to_trade_for_trigger_mark…
crispheaney Mar 2, 2022
93fd2ca
clearing_house: make round in favor work with placeAndFill
crispheaney Feb 28, 2022
29303c4
Merge remote-tracking branch 'origin/master' into bigz/formualic-repeg
Mar 9, 2022
f8dee80
merge master
Mar 9, 2022
5868cc5
repeg: use new oracle data and write budget function
Mar 10, 2022
967da1c
Merge remote-tracking branch 'origin/master' into bigz/formualic-repeg
Mar 16, 2022
a50ceb6
formulaic repeg after fill order, start budget k
Mar 16, 2022
9b7f362
merge master
Mar 18, 2022
84c19ca
merged switchboard, fmt
Mar 20, 2022
5ad3c1e
add budget k
Mar 21, 2022
05cdffe
add formulaPeg and formualK tests
Mar 21, 2022
18e4790
repeg use fspr
Mar 22, 2022
cac6ef4
more test examples
Mar 22, 2022
58f4891
cleanup controller/math for repeg
Mar 23, 2022
41830cc
add formulaK.ts
Mar 23, 2022
4138a51
merge master
Mar 23, 2022
7c3e11c
fix typo
Mar 24, 2022
fa80469
repeg only
Mar 24, 2022
8c624d4
remove all adj k
Mar 24, 2022
80d1956
cleanup for merge
Mar 24, 2022
ed29604
address comments p1
Mar 24, 2022
665f7e0
comments p2
Mar 24, 2022
36a288d
fix bug
Mar 24, 2022
23636bc
Merge branch 'bigz/formualic-repeg' into formulaic-k
Mar 24, 2022
d1c5327
add back k budget
Mar 25, 2022
3e48e76
merge master
Apr 4, 2022
5333cd4
resolve conflicts
Apr 4, 2022
0399928
init
Apr 4, 2022
5ead517
form-k: fix complier errors
Apr 5, 2022
b76d3e7
sdk: add NEAR
crispheaney Apr 4, 2022
21eeff9
export math/repeg.ts, remove redudant amm.ts
Apr 4, 2022
aae07e6
amm.ts: remove unused imports
Apr 4, 2022
5ee1f66
sdk: use pyth aggregate price for oracle price
crispheaney Apr 4, 2022
7eaeab6
sdk: release v0.1.29
crispheaney Apr 4, 2022
eea4332
segment adjust and update for k
Apr 6, 2022
e1effd3
repeg: calculate target price as a function of oracle delay and norma…
Apr 7, 2022
ff1b716
fix merge conflict
Apr 7, 2022
aa7d1c3
Merge remote-tracking branch 'origin/master' into formulaic-k
Apr 7, 2022
de7ab64
address github comments
Apr 12, 2022
08da5f2
working formulaic k test cases (todo: rm debugging statements)
Apr 13, 2022
d52e6c6
optimize formulaic repeg
crispheaney Apr 18, 2022
f208be3
some optimizations for formulaic k, avoid calculating funding_imbalan…
crispheaney Apr 18, 2022
cac091a
optimize calculate_budgeted_k_scale
crispheaney Apr 20, 2022
acd64bd
remove extra sol_log_compute_units
crispheaney Apr 20, 2022
478f276
use U128 for cheaper multiplications
crispheaney Apr 20, 2022
466dd7f
only calculate update k result once
crispheaney Apr 20, 2022
7b6fd9b
use 192 instead of 256 for k maths
crispheaney Apr 20, 2022
30831d6
pass around trade record
crispheaney Apr 20, 2022
be98bee
optimize calculate_oracle_mark_spread_pct
crispheaney Apr 20, 2022
e9e15e0
pass mark_price_after to update_funding_rate
crispheaney Apr 20, 2022
8a1d9d9
add update_intensity, add repeg bounds
Apr 21, 2022
03b3a32
rename update_intensity to curve_update_intensity
Apr 22, 2022
441ffbe
add curve history as optional to open and close position
crispheaney Apr 29, 2022
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
5 changes: 5 additions & 0 deletions programs/clearing_house/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,11 @@ pub struct UpdateFundingRate<'info> {
constraint = &state.funding_rate_history.eq(&funding_rate_history.key())
)]
pub funding_rate_history: AccountLoader<'info, FundingRateHistory>,
#[account(
mut,
constraint = &state.extended_curve_history.eq(&extended_curve_history.key())
)]
pub extended_curve_history: AccountLoader<'info, ExtendedCurveHistory>,
}

#[derive(Accounts)]
Expand Down
103 changes: 101 additions & 2 deletions programs/clearing_house/src/controller/amm.rs
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 {
Expand Down Expand Up @@ -92,6 +97,100 @@ pub fn move_price(
Ok(())
}

pub fn formulaic_k(
Copy link
Member

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

market: &mut Market,
mark_price: u128,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused

oracle_price_data: &OraclePriceData,
is_oracle_valid: bool,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused

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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

casting i128 to i64 can technically fail, so i'd use cast_to_i64.

Also i'd just declare it once instead of casting twice

let funding_imbalance_cost_i64 = cast_to_i64(funding_imbalance_cost)?;

// 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)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does p stand for?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p * k_old = k_new (notation from a paper)


if p_numer > p_denom {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok for devnet but ideally we dont include since it's expensive to add msg!

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);
Expand Down
35 changes: 33 additions & 2 deletions programs/clearing_house/src/controller/funding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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;
Expand Down Expand Up @@ -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>,
Expand All @@ -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;
Expand Down Expand Up @@ -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)?,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be a constant

)
.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
Expand Down
7 changes: 4 additions & 3 deletions programs/clearing_house/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -800,23 +800,24 @@ pub fn fill_order(
let funding_rate_history = &mut funding_rate_history
.load_mut()
.or(Err(ErrorCode::UnableToLoadAccountLoader))?;
let extended_curve_history = &mut extended_curve_history
.load_mut()
.or(Err(ErrorCode::UnableToLoadAccountLoader))?;
controller::funding::update_funding_rate(
market_index,
market,
oracle,
now,
clock_slot,
funding_rate_history,
Some(extended_curve_history),
&state.oracle_guard_rails,
state.funding_paused,
Some(mark_price_before),
)?;

// if market_index >= 12 {
// todo for soft launch
let extended_curve_history = &mut extended_curve_history
.load_mut()
.or(Err(ErrorCode::UnableToLoadAccountLoader))?;

controller::repeg::formulaic_repeg(
market,
Expand Down
8 changes: 4 additions & 4 deletions programs/clearing_house/src/controller/repeg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ pub fn formulaic_repeg(
) -> ClearingHouseResult<i128> {
// backrun market swaps to do automatic on-chain repeg

if !is_oracle_valid || oracle_price_data.delay > 5 {
if !is_oracle_valid {
msg!(
"invalid oracle (oracle delay = {:?})",
"skipping formulaic_repeg: invalid oracle (oracle delay = {:?})",
oracle_price_data.delay
);
return Ok(0);
Expand All @@ -115,7 +115,7 @@ pub fn formulaic_repeg(
terminal_quote_reserves,
repeg_budget,
mark_price,
cast_to_u128(oracle_price_data.price)?,
oracle_price_data,
)?;

let (
Expand Down Expand Up @@ -172,7 +172,7 @@ pub fn formulaic_repeg(
Ok(adjustment_cost)
}

fn apply_cost_to_market(market: &mut Market, cost: i128) -> ClearingHouseResult<bool> {
pub fn apply_cost_to_market(market: &mut Market, cost: i128) -> ClearingHouseResult<bool> {
// positive cost is expense, negative cost is revenue
// Reduce pnl to quote asset precision and take the absolute value
if cost > 0 {
Expand Down
16 changes: 15 additions & 1 deletion programs/clearing_house/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,7 @@ pub mod clearing_house {
now,
clock_slot,
funding_rate_history,
None,
&ctx.accounts.state.oracle_guard_rails,
ctx.accounts.state.funding_paused,
Some(mark_price_before),
Expand Down Expand Up @@ -959,6 +960,7 @@ pub mod clearing_house {
now,
clock_slot,
funding_rate_history,
None,
&ctx.accounts.state.oracle_guard_rails,
ctx.accounts.state.funding_paused,
Some(mark_price_before),
Expand Down Expand Up @@ -2079,13 +2081,20 @@ pub mod clearing_house {
let clock_slot = clock.slot;

let funding_rate_history = &mut ctx.accounts.funding_rate_history.load_mut()?;
let extended_curve_history = &mut ctx
.accounts
.extended_curve_history
.load_mut()
.or(Err(ErrorCode::UnableToLoadAccountLoader))?;

controller::funding::update_funding_rate(
market_index,
market,
price_oracle,
now,
clock_slot,
funding_rate_history,
Some(extended_curve_history),
&ctx.accounts.state.oracle_guard_rails,
ctx.accounts.state.funding_paused,
None,
Expand Down Expand Up @@ -2123,7 +2132,12 @@ pub mod clearing_house {
let quote_asset_reserve_before = market.amm.quote_asset_reserve;
let sqrt_k_before = market.amm.sqrt_k;

let adjustment_cost = math::amm::adjust_k_cost(market, bn::U256::from(sqrt_k))?;
let new_sqrt_k_U256 = bn::U256::from(sqrt_k);

let (mut adjust_k_market, adjustment_cost) =
math::amm::adjust_k_cost(market, new_sqrt_k_U256)?;

math::amm::update_k(market, new_sqrt_k_U256);

if adjustment_cost > 0 {
let max_cost = market
Expand Down
Loading