Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
26 changes: 19 additions & 7 deletions programs/drift/src/controller/amm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,16 +185,28 @@ pub fn update_spreads(
let max_ref_offset = market.amm.get_max_reference_price_offset()?;

let reference_price_offset = if max_ref_offset > 0 {
let liquidity_ratio = amm_spread::calculate_inventory_liquidity_ratio(
market.amm.base_asset_amount_with_amm,
market.amm.base_asset_reserve,
market.amm.min_base_asset_reserve,
market.amm.max_base_asset_reserve,
)?;
let liquidity_ratio =
amm_spread::calculate_inventory_liquidity_ratio_for_reference_price_offset(
market.amm.base_asset_amount_with_amm,
market.amm.base_asset_reserve,
market.amm.min_base_asset_reserve,
market.amm.max_base_asset_reserve,
)?;

let signed_liquidity_ratio =
let mut signed_liquidity_ratio =
liquidity_ratio.safe_mul(market.amm.get_protocol_owned_position()?.signum().cast()?)?;

let deadband_pct = market.amm.get_reference_price_offset_deadband_pct()?;
if signed_liquidity_ratio.unsigned_abs() <= deadband_pct {
signed_liquidity_ratio = 0;
} else {
signed_liquidity_ratio = signed_liquidity_ratio.safe_sub(
deadband_pct
.cast::<i128>()?
.safe_mul(signed_liquidity_ratio.signum())?,
)?;
}

amm_spread::calculate_reference_price_offset(
reserve_price,
market.amm.last_24h_avg_funding_rate,
Expand Down
53 changes: 25 additions & 28 deletions programs/drift/src/controller/position/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ fn amm_ref_price_offset_decay_logic() {
.unwrap();
assert_eq!(perp_market.amm.last_update_slot, clock_slot);
assert_eq!(perp_market.amm.last_oracle_valid, true);
assert_eq!(perp_market.amm.reference_price_offset, 7350);
assert_eq!(perp_market.amm.reference_price_offset, 4458);

perp_market.amm.last_mark_price_twap_5min = (perp_market
.amm
Expand Down Expand Up @@ -893,28 +893,28 @@ fn amm_ref_price_offset_decay_logic() {
assert_eq!(
offsets,
[
7140, 6930, 6720, 6510, 6300, 6090, 6070, 6050, 6030, 6010, 5800, 5590, 5380, 5170,
4960, 4750, 4540, 4330, 4120, 3910, 3700, 3490, 3280, 3070, 2860, 2650, 2440, 2230,
2020, 1810, 1620, 1449, 1296, 1158, 1034, 922, 821, 730, 648, 575, 509, 450, 396, 348,
305, 266, 231, 199, 171, 145, 122, 101, 81, 61, 41, 21, 1, 0, 0, 0
4248, 4038, 3828, 3618, 3408, 3198, 3178, 3158, 3138, 3118, 2908, 2698, 2488, 2278,
2068, 1858, 1664, 1489, 1332, 1190, 1062, 947, 844, 751, 667, 592, 524, 463, 408, 359,
315, 275, 239, 207, 178, 152, 128, 107, 87, 67, 47, 27, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
]
);
assert_eq!(
lspreads,
[
726, 726, 726, 726, 726, 726, 536, 536, 536, 536, 726, 726, 726, 726, 726, 726, 726,
726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 706, 687, 669, 654,
640, 628, 617, 607, 598, 589, 582, 575, 570, 564, 559, 555, 551, 548, 544, 542, 539,
537, 536, 536, 536, 536, 536, 526, 526, 526
726, 726, 726, 726, 726, 726, 536, 536, 536, 536, 726, 726, 726, 726, 726, 726, 710,
691, 673, 658, 644, 631, 619, 609, 600, 591, 584, 577, 571, 565, 560, 556, 552, 548,
545, 542, 540, 537, 536, 536, 536, 536, 536, 526, 526, 526, 526, 526, 526, 526, 526,
526, 526, 526, 526, 526, 526, 526, 526, 526
]
);
assert_eq!(
sspreads,
[
7150, 6940, 6730, 6520, 6310, 6100, 6080, 6060, 6040, 6020, 5810, 5600, 5390, 5180,
4970, 4760, 4550, 4340, 4130, 3920, 3710, 3500, 3290, 3080, 2870, 2660, 2450, 2240,
2030, 1820, 1630, 1459, 1306, 1168, 1044, 932, 831, 740, 658, 585, 519, 460, 406, 358,
315, 276, 241, 209, 181, 155, 132, 111, 91, 71, 51, 31, 11, 10, 10, 10
4258, 4048, 3838, 3628, 3418, 3208, 3188, 3168, 3148, 3128, 2918, 2708, 2498, 2288,
2078, 1868, 1674, 1499, 1342, 1200, 1072, 957, 854, 761, 677, 602, 534, 473, 418, 369,
325, 285, 249, 217, 188, 162, 138, 117, 97, 77, 57, 37, 17, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10
]
);
}
Expand Down Expand Up @@ -1017,7 +1017,7 @@ fn amm_negative_ref_price_offset_decay_logic() {
.unwrap();
assert_eq!(perp_market.amm.last_update_slot, clock_slot);
assert_eq!(perp_market.amm.last_oracle_valid, true);
assert_eq!(perp_market.amm.reference_price_offset, 7350);
assert_eq!(perp_market.amm.reference_price_offset, 4458);

perp_market.amm.last_mark_price_twap_5min = (perp_market
.amm
Expand Down Expand Up @@ -1068,34 +1068,31 @@ fn amm_negative_ref_price_offset_decay_logic() {
assert_eq!(
offsets,
[
-7140, -6930, -6720, -6510, -6300, -6090, -6070, -6050, -6030, -6010, -5800, -5590,
-5380, -5170, -4960, -4750, -4540, -4330, -4120, -3910, -3700, -3490, -3280, -3070,
-2860, -2650, -2440, -2230, -2020, -1810, -1600, -1390, -1180, -970, -760, -550, -340,
-130, 0, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000,
10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000,
10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000,
10000, 10000, 10000, 10000, 10000, 10000
-4248, -4038, -3828, -3618, -3408, -3198, -3178, -3158, -3138, -3118, -2908, -2698,
-2488, -2278, -2068, -1858, -1648, -1438, -1228, -1018, -808, -598, -388, -178, 0,
7654, 7652, 7651, 7649, 7648, 7646, 7645, 7643, 7641, 7640, 7638, 7637, 7635, 7634,
7632, 7631, 7629, 7628, 7626, 7625, 7623, 7622, 7620, 7619, 7618, 7616, 7615, 7613,
7612, 7610, 7609, 7607, 7606, 7605, 7603, 7602, 7600, 7599, 7597, 7596, 7595, 7593,
7592, 7591, 7589, 7588, 7586, 7585, 7584, 7582, 7581, 7580, 7578, 7577, 7576
]
);
assert_eq!(
sspreads,
[
210, 210, 210, 210, 210, 210, 20, 20, 20, 20, 210, 210, 210, 210, 210, 210, 210, 210,
210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
210, 210, 210, 130, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
210, 210, 210, 210, 210, 210, 178, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
]
);
assert_eq!(
lspreads,
[
7666, 7456, 7246, 7036, 6826, 6616, 6596, 6576, 6556, 6536, 6326, 6116, 5906, 5696,
5486, 5276, 5066, 4856, 4646, 4436, 4226, 4016, 3806, 3596, 3386, 3176, 2966, 2756,
2546, 2336, 2126, 1916, 1706, 1496, 1286, 1076, 866, 656, 526, 526, 526, 526, 526, 526,
4774, 4564, 4354, 4144, 3934, 3724, 3704, 3684, 3664, 3644, 3434, 3224, 3014, 2804,
2594, 2384, 2174, 1964, 1754, 1544, 1334, 1124, 914, 704, 526, 526, 526, 526, 526, 526,
526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526,
526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526,
526, 526
526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526
]
);
}
Expand Down
28 changes: 27 additions & 1 deletion programs/drift/src/instructions/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1079,7 +1079,8 @@ pub fn handle_initialize_perp_market(
quote_asset_amount_with_unsettled_lp: 0,
reference_price_offset: 0,
amm_inventory_spread_adjustment: 0,
padding: [0; 3],
reference_price_offset_deadband_pct: 0,
padding: [0; 2],
last_funding_oracle_twap: 0,
},
};
Expand Down Expand Up @@ -3439,6 +3440,31 @@ pub fn handle_update_perp_market_curve_update_intensity(
Ok(())
}

#[access_control(
perp_market_valid(&ctx.accounts.perp_market)
)]
pub fn handle_update_perp_market_reference_price_offset_deadband_pct(
ctx: Context<HotAdminUpdatePerpMarket>,
reference_price_offset_deadband_pct: u8,
) -> Result<()> {
validate!(
reference_price_offset_deadband_pct <= 100,
ErrorCode::DefaultError,
"invalid reference_price_offset_deadband_pct",
)?;
let perp_market = &mut load_mut!(ctx.accounts.perp_market)?;
msg!("perp market {}", perp_market.market_index);

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

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

pub fn handle_update_lp_cooldown_time(
ctx: Context<AdminUpdateState>,
lp_cooldown_time: u64,
Expand Down
10 changes: 10 additions & 0 deletions programs/drift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,16 @@ pub mod drift {
handle_update_perp_market_curve_update_intensity(ctx, curve_update_intensity)
}

pub fn update_perp_market_reference_price_offset_deadband_pct(
ctx: Context<HotAdminUpdatePerpMarket>,
reference_price_offset_deadband_pct: u8,
) -> Result<()> {
handle_update_perp_market_reference_price_offset_deadband_pct(
ctx,
reference_price_offset_deadband_pct,
)
}

pub fn update_lp_cooldown_time(
ctx: Context<AdminUpdateState>,
lp_cooldown_time: u64,
Expand Down
37 changes: 34 additions & 3 deletions programs/drift/src/math/amm_spread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use crate::math::constants::{
BID_ASK_SPREAD_PRECISION, BID_ASK_SPREAD_PRECISION_I128, DEFAULT_LARGE_BID_ASK_FACTOR,
DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT, FUNDING_RATE_BUFFER,
MAX_BID_ASK_INVENTORY_SKEW_FACTOR, PEG_PRECISION, PERCENTAGE_PRECISION,
PERCENTAGE_PRECISION_I128, PERCENTAGE_PRECISION_U64, PRICE_PRECISION, PRICE_PRECISION_I128,
PRICE_PRECISION_I64,
PERCENTAGE_PRECISION_I128, PERCENTAGE_PRECISION_I64, PERCENTAGE_PRECISION_U64, PRICE_PRECISION,
PRICE_PRECISION_I128, PRICE_PRECISION_I64,
};
use crate::math::safe_math::SafeMath;
use crate::state::perp_market::{ContractType, PerpMarket, AMM};
Expand Down Expand Up @@ -193,6 +193,37 @@ pub fn calculate_inventory_liquidity_ratio(
Ok(amm_inventory_pct)
}

pub fn calculate_inventory_liquidity_ratio_for_reference_price_offset(
base_asset_amount_with_amm: i128,
base_asset_reserve: u128,
min_base_asset_reserve: u128,
max_base_asset_reserve: u128,
) -> DriftResult<i128> {
// computes min(1, x/(1-x)) for 0 < x < 1

// inventory scale
let (max_bids, max_asks) = _calculate_market_open_bids_asks(
base_asset_reserve,
min_base_asset_reserve,
max_base_asset_reserve,
)?;

let avg_liquidity = (max_bids.safe_add(max_asks.abs())?).safe_div(2)?;

let amm_inventory_pct = if base_asset_amount_with_amm.abs() < avg_liquidity {
base_asset_amount_with_amm
.abs()
.safe_mul(PERCENTAGE_PRECISION_I128)
.unwrap_or(i128::MAX)
.safe_div(avg_liquidity.max(1))?
.min(PERCENTAGE_PRECISION_I128)
} else {
PERCENTAGE_PRECISION_I128 // 100%
};

Ok(amm_inventory_pct)
}

pub fn calculate_spread_inventory_scale(
base_asset_amount_with_amm: i128,
base_asset_reserve: u128,
Expand Down Expand Up @@ -570,7 +601,7 @@ pub fn calculate_reference_price_offset(
mark_twap_slow: u64,
max_offset_pct: i64,
) -> DriftResult<i32> {
if last_24h_avg_funding_rate == 0 {
if last_24h_avg_funding_rate == 0 || liquidity_fraction == 0 {
return Ok(0);
}

Expand Down
43 changes: 43 additions & 0 deletions programs/drift/src/math/amm_spread/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#[cfg(test)]
mod test {
use crate::controller::amm::update_spreads;
use crate::math::amm::calculate_price;
use crate::math::amm_spread::*;
use crate::math::constants::{
Expand Down Expand Up @@ -189,6 +190,48 @@ mod test {
assert_eq!(res, 0);
}

#[test]
fn calculate_reference_price_offset_deadband_tests() {
let mut market = PerpMarket {
amm: AMM {
base_asset_reserve: AMM_RESERVE_PRECISION * 11,
quote_asset_reserve: AMM_RESERVE_PRECISION * 10,
sqrt_k: AMM_RESERVE_PRECISION * 10,
peg_multiplier: 34_000_000,
min_base_asset_reserve: AMM_RESERVE_PRECISION * 7,
max_base_asset_reserve: AMM_RESERVE_PRECISION * 14,
base_spread: 1000,
max_spread: 20_000,
curve_update_intensity: 110,
last_24h_avg_funding_rate: 1,
last_mark_price_twap_5min: 4216 * 10000 + 2 * 10000,
last_mark_price_twap: 4216 * 10000 + 2 * 10000,
historical_oracle_data: {
let mut hod: crate::state::oracle::HistoricalOracleData = Default::default();
hod.last_oracle_price_twap_5min = 4216 * 10000;
hod.last_oracle_price_twap = 4216 * 10000;
hod
},
..AMM::default()
},
..PerpMarket::default()
};

let reserve_price = 4216 * 10000;

let max_ref_offset = market.amm.get_max_reference_price_offset().unwrap();
assert_eq!(max_ref_offset, 10000);
market.amm.base_asset_amount_with_amm = (AMM_RESERVE_PRECISION * 3 / 20) as i128;
let (_l, _s) = update_spreads(&mut market, reserve_price as u64, None).unwrap();
assert_eq!(market.amm.reference_price_offset, 10);

// If base asset amount with amm is small, reference price offset is 0
market.amm.reference_price_offset_deadband_pct = 10;
market.amm.base_asset_amount_with_amm = (AMM_RESERVE_PRECISION * 3 / 20) as i128;
let (_l, _s) = update_spreads(&mut market, reserve_price as u64, None).unwrap();
assert_eq!(market.amm.reference_price_offset, 0);
}

#[test]
fn calculate_spread_tests() {
let base_spread = 1000; // .1%
Expand Down
10 changes: 8 additions & 2 deletions programs/drift/src/state/perp_market.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1167,7 +1167,8 @@ pub struct AMM {
pub reference_price_offset: i32,
/// signed scale amm_spread similar to fee_adjustment logic (-100 = 0, 100 = double)
pub amm_inventory_spread_adjustment: i8,
pub padding: [u8; 3],
pub reference_price_offset_deadband_pct: u8,
pub padding: [u8; 2],
pub last_funding_oracle_twap: i64,
}

Expand Down Expand Up @@ -1258,13 +1259,18 @@ impl Default for AMM {
quote_asset_amount_with_unsettled_lp: 0,
reference_price_offset: 0,
amm_inventory_spread_adjustment: 0,
padding: [0; 3],
reference_price_offset_deadband_pct: 0,
padding: [0; 2],
last_funding_oracle_twap: 0,
}
}
}

impl AMM {
pub fn get_reference_price_offset_deadband_pct(&self) -> DriftResult<u128> {
let pct = self.reference_price_offset_deadband_pct as u128;
Ok(PERCENTAGE_PRECISION.safe_mul(pct)?.safe_div(100_u128)?)
}
pub fn get_fallback_price(
self,
direction: &PositionDirection,
Expand Down
40 changes: 40 additions & 0 deletions sdk/src/adminClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,46 @@ export class AdminClient extends DriftClient {
);
}

public async updatePerpMarketReferencePriceOffsetDeadbandPct(
perpMarketIndex: number,
referencePriceOffsetDeadbandPct: number
): Promise<TransactionSignature> {
const updatePerpMarketReferencePriceOffsetDeadbandPctIx =
await this.getUpdatePerpMarketReferencePriceOffsetDeadbandPctIx(
perpMarketIndex,
referencePriceOffsetDeadbandPct
);

const tx = await this.buildTransaction(
updatePerpMarketReferencePriceOffsetDeadbandPctIx
);

const { txSig } = await this.sendTransaction(tx, [], this.opts);

return txSig;
}

public async getUpdatePerpMarketReferencePriceOffsetDeadbandPctIx(
perpMarketIndex: number,
referencePriceOffsetDeadbandPct: number
): Promise<TransactionInstruction> {
return await this.program.instruction.updatePerpMarketReferencePriceOffsetDeadbandPct(
referencePriceOffsetDeadbandPct,
{
accounts: {
admin: this.useHotWalletAdmin
? this.wallet.publicKey
: this.getStateAccount().admin,
state: await this.getStatePublicKey(),
perpMarket: await getPerpMarketPublicKey(
this.program.programId,
perpMarketIndex
),
},
}
);
}

public async updatePerpMarketTargetBaseAssetAmountPerLp(
perpMarketIndex: number,
targetBaseAssetAmountPerLP: number
Expand Down
Loading
Loading