Skip to content

Commit 8192cff

Browse files
committed
add admin function + move field to amm + sdk math
1 parent 3774ca0 commit 8192cff

File tree

10 files changed

+188
-31
lines changed

10 files changed

+188
-31
lines changed

programs/drift/src/controller/amm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ pub fn update_spreads(
196196
let mut signed_liquidity_ratio =
197197
liquidity_ratio.safe_mul(market.amm.get_protocol_owned_position()?.signum().cast()?)?;
198198

199-
let deadband_pct = market.get_reference_offset_deadband_pct()?;
199+
let deadband_pct = market.amm.get_reference_price_offset_deadband_pct()?;
200200
if signed_liquidity_ratio.unsigned_abs() <= deadband_pct {
201201
signed_liquidity_ratio = 0;
202202
} else {

programs/drift/src/instructions/admin.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -983,8 +983,7 @@ pub fn handle_initialize_perp_market(
983983
protected_maker_dynamic_divisor: 0,
984984
padding1: 0,
985985
last_fill_price: 0,
986-
reference_offset_deadband_pct: 0,
987-
padding: [0; 23],
986+
padding: [0; 24],
988987
amm: AMM {
989988
oracle: *ctx.accounts.oracle.key,
990989
oracle_source,
@@ -1080,7 +1079,8 @@ pub fn handle_initialize_perp_market(
10801079
quote_asset_amount_with_unsettled_lp: 0,
10811080
reference_price_offset: 0,
10821081
amm_inventory_spread_adjustment: 0,
1083-
padding: [0; 3],
1082+
reference_price_offset_deadband_pct: 0,
1083+
padding: [0; 2],
10841084
last_funding_oracle_twap: 0,
10851085
},
10861086
};
@@ -3440,6 +3440,31 @@ pub fn handle_update_perp_market_curve_update_intensity(
34403440
Ok(())
34413441
}
34423442

3443+
#[access_control(
3444+
perp_market_valid(&ctx.accounts.perp_market)
3445+
)]
3446+
pub fn handle_update_perp_market_reference_price_offset_deadband_pct(
3447+
ctx: Context<HotAdminUpdatePerpMarket>,
3448+
reference_price_offset_deadband_pct: u8,
3449+
) -> Result<()> {
3450+
validate!(
3451+
reference_price_offset_deadband_pct <= 100,
3452+
ErrorCode::DefaultError,
3453+
"invalid reference_price_offset_deadband_pct",
3454+
)?;
3455+
let perp_market = &mut load_mut!(ctx.accounts.perp_market)?;
3456+
msg!("perp market {}", perp_market.market_index);
3457+
3458+
msg!(
3459+
"perp_market.amm.reference_price_offset_deadband_pct: {} -> {}",
3460+
perp_market.amm.reference_price_offset_deadband_pct,
3461+
reference_price_offset_deadband_pct
3462+
);
3463+
3464+
perp_market.amm.reference_price_offset_deadband_pct = reference_price_offset_deadband_pct;
3465+
Ok(())
3466+
}
3467+
34433468
pub fn handle_update_lp_cooldown_time(
34443469
ctx: Context<AdminUpdateState>,
34453470
lp_cooldown_time: u64,

programs/drift/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,6 +1387,16 @@ pub mod drift {
13871387
handle_update_perp_market_curve_update_intensity(ctx, curve_update_intensity)
13881388
}
13891389

1390+
pub fn update_perp_market_reference_price_offset_deadband_pct(
1391+
ctx: Context<HotAdminUpdatePerpMarket>,
1392+
reference_price_offset_deadband_pct: u8,
1393+
) -> Result<()> {
1394+
handle_update_perp_market_reference_price_offset_deadband_pct(
1395+
ctx,
1396+
reference_price_offset_deadband_pct,
1397+
)
1398+
}
1399+
13901400
pub fn update_lp_cooldown_time(
13911401
ctx: Context<AdminUpdateState>,
13921402
lp_cooldown_time: u64,

programs/drift/src/math/amm_spread/tests.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,6 @@ mod test {
214214
},
215215
..AMM::default()
216216
},
217-
reference_offset_deadband_pct: 0,
218217
..PerpMarket::default()
219218
};
220219

@@ -227,7 +226,7 @@ mod test {
227226
assert_eq!(market.amm.reference_price_offset, 10);
228227

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

programs/drift/src/state/perp_market.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,7 @@ pub struct PerpMarket {
236236
pub protected_maker_dynamic_divisor: u8,
237237
pub padding1: u32,
238238
pub last_fill_price: u64,
239-
/// Reference price offset deadband percentage (0-100). 0 disables deadband.
240-
/// Stored in former padding to preserve zero-copy layout.
241-
pub reference_offset_deadband_pct: u8,
242-
pub padding: [u8; 23],
239+
pub padding: [u8; 24],
243240
}
244241

245242
impl Default for PerpMarket {
@@ -283,8 +280,7 @@ impl Default for PerpMarket {
283280
protected_maker_dynamic_divisor: 0,
284281
padding1: 0,
285282
last_fill_price: 0,
286-
reference_offset_deadband_pct: 0,
287-
padding: [0; 23],
283+
padding: [0; 24],
288284
}
289285
}
290286
}
@@ -298,10 +294,6 @@ impl MarketIndexOffset for PerpMarket {
298294
}
299295

300296
impl PerpMarket {
301-
pub fn get_reference_offset_deadband_pct(&self) -> DriftResult<u128> {
302-
let pct = self.reference_offset_deadband_pct as u128;
303-
Ok(PERCENTAGE_PRECISION.safe_mul(pct)?.safe_div(100_u128)?)
304-
}
305297
pub fn oracle_id(&self) -> OracleIdentifier {
306298
(self.amm.oracle, self.amm.oracle_source)
307299
}
@@ -1175,7 +1167,8 @@ pub struct AMM {
11751167
pub reference_price_offset: i32,
11761168
/// signed scale amm_spread similar to fee_adjustment logic (-100 = 0, 100 = double)
11771169
pub amm_inventory_spread_adjustment: i8,
1178-
pub padding: [u8; 3],
1170+
pub reference_price_offset_deadband_pct: u8,
1171+
pub padding: [u8; 2],
11791172
pub last_funding_oracle_twap: i64,
11801173
}
11811174

@@ -1266,13 +1259,18 @@ impl Default for AMM {
12661259
quote_asset_amount_with_unsettled_lp: 0,
12671260
reference_price_offset: 0,
12681261
amm_inventory_spread_adjustment: 0,
1269-
padding: [0; 3],
1262+
reference_price_offset_deadband_pct: 0,
1263+
padding: [0; 2],
12701264
last_funding_oracle_twap: 0,
12711265
}
12721266
}
12731267
}
12741268

12751269
impl AMM {
1270+
pub fn get_reference_price_offset_deadband_pct(&self) -> DriftResult<u128> {
1271+
let pct = self.reference_price_offset_deadband_pct as u128;
1272+
Ok(PERCENTAGE_PRECISION.safe_mul(pct)?.safe_div(100_u128)?)
1273+
}
12761274
pub fn get_fallback_price(
12771275
self,
12781276
direction: &PositionDirection,

sdk/src/adminClient.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,46 @@ export class AdminClient extends DriftClient {
12321232
);
12331233
}
12341234

1235+
public async updatePerpMarketReferencePriceOffsetDeadbandPct(
1236+
perpMarketIndex: number,
1237+
referencePriceOffsetDeadbandPct: number
1238+
): Promise<TransactionSignature> {
1239+
const updatePerpMarketReferencePriceOffsetDeadbandPctIx =
1240+
await this.getUpdatePerpMarketReferencePriceOffsetDeadbandPctIx(
1241+
perpMarketIndex,
1242+
referencePriceOffsetDeadbandPct
1243+
);
1244+
1245+
const tx = await this.buildTransaction(
1246+
updatePerpMarketReferencePriceOffsetDeadbandPctIx
1247+
);
1248+
1249+
const { txSig } = await this.sendTransaction(tx, [], this.opts);
1250+
1251+
return txSig;
1252+
}
1253+
1254+
public async getUpdatePerpMarketReferencePriceOffsetDeadbandPctIx(
1255+
perpMarketIndex: number,
1256+
referencePriceOffsetDeadbandPct: number
1257+
): Promise<TransactionInstruction> {
1258+
return await this.program.instruction.updatePerpMarketReferencePriceOffsetDeadbandPct(
1259+
referencePriceOffsetDeadbandPct,
1260+
{
1261+
accounts: {
1262+
admin: this.useHotWalletAdmin
1263+
? this.wallet.publicKey
1264+
: this.getStateAccount().admin,
1265+
state: await this.getStatePublicKey(),
1266+
perpMarket: await getPerpMarketPublicKey(
1267+
this.program.programId,
1268+
perpMarketIndex
1269+
),
1270+
},
1271+
}
1272+
);
1273+
}
1274+
12351275
public async updatePerpMarketTargetBaseAssetAmountPerLp(
12361276
perpMarketIndex: number,
12371277
targetBaseAssetAmountPerLP: number

sdk/src/idl/drift.json

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5874,6 +5874,32 @@
58745874
}
58755875
]
58765876
},
5877+
{
5878+
"name": "updatePerpMarketReferencePriceOffsetDeadbandPct",
5879+
"accounts": [
5880+
{
5881+
"name": "admin",
5882+
"isMut": false,
5883+
"isSigner": true
5884+
},
5885+
{
5886+
"name": "state",
5887+
"isMut": false,
5888+
"isSigner": false
5889+
},
5890+
{
5891+
"name": "perpMarket",
5892+
"isMut": true,
5893+
"isSigner": false
5894+
}
5895+
],
5896+
"args": [
5897+
{
5898+
"name": "referencePriceOffsetDeadbandPct",
5899+
"type": "u8"
5900+
}
5901+
]
5902+
},
58775903
{
58785904
"name": "updateLpCooldownTime",
58795905
"accounts": [
@@ -11209,12 +11235,16 @@
1120911235
],
1121011236
"type": "i8"
1121111237
},
11238+
{
11239+
"name": "referencePriceOffsetDeadbandPct",
11240+
"type": "u8"
11241+
},
1121211242
{
1121311243
"name": "padding",
1121411244
"type": {
1121511245
"array": [
1121611246
"u8",
11217-
3
11247+
2
1121811248
]
1121911249
}
1122011250
},
@@ -16782,8 +16812,5 @@
1678216812
"name": "UnableToLoadRevenueShareAccount",
1678316813
"msg": "Unable to load builder account"
1678416814
}
16785-
],
16786-
"metadata": {
16787-
"address": "dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH"
16788-
}
16815+
]
1678916816
}

sdk/src/math/amm.ts

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,31 @@ export function calculateInventoryLiquidityRatio(
389389
return inventoryScaleBN;
390390
}
391391

392+
export function calculateInventoryLiquidityRatioForReferencePriceOffset(
393+
baseAssetAmountWithAmm: BN,
394+
baseAssetReserve: BN,
395+
minBaseAssetReserve: BN,
396+
maxBaseAssetReserve: BN
397+
): BN {
398+
// inventory skew
399+
const [openBids, openAsks] = calculateMarketOpenBidAsk(
400+
baseAssetReserve,
401+
minBaseAssetReserve,
402+
maxBaseAssetReserve
403+
);
404+
405+
const minSideLiquidity = openBids.abs().add(openAsks.abs()).div(TWO);
406+
407+
const inventoryScaleBN = BN.min(
408+
baseAssetAmountWithAmm
409+
.mul(PERCENTAGE_PRECISION)
410+
.div(BN.max(minSideLiquidity, ONE))
411+
.abs(),
412+
PERCENTAGE_PRECISION
413+
);
414+
return inventoryScaleBN;
415+
}
416+
392417
export function calculateInventoryScale(
393418
baseAssetAmountWithAmm: BN,
394419
baseAssetReserve: BN,
@@ -440,7 +465,7 @@ export function calculateReferencePriceOffset(
440465
markTwapSlow: BN,
441466
maxOffsetPct: number
442467
): BN {
443-
if (last24hAvgFundingRate.eq(ZERO)) {
468+
if (last24hAvgFundingRate.eq(ZERO) || liquidityFraction.eq(ZERO)) {
444469
return ZERO;
445470
}
446471

@@ -1013,19 +1038,38 @@ export function calculateSpreadReserves(
10131038
(amm.curveUpdateIntensity - 100)
10141039
);
10151040

1016-
const liquidityFraction = calculateInventoryLiquidityRatio(
1017-
amm.baseAssetAmountWithAmm,
1018-
amm.baseAssetReserve,
1019-
amm.minBaseAssetReserve,
1020-
amm.maxBaseAssetReserve
1021-
);
1041+
const liquidityFraction =
1042+
calculateInventoryLiquidityRatioForReferencePriceOffset(
1043+
amm.baseAssetAmountWithAmm,
1044+
amm.baseAssetReserve,
1045+
amm.minBaseAssetReserve,
1046+
amm.maxBaseAssetReserve
1047+
);
10221048
const liquidityFractionSigned = liquidityFraction.mul(
10231049
sigNum(amm.baseAssetAmountWithAmm.add(amm.baseAssetAmountWithUnsettledLp))
10241050
);
1051+
1052+
let liquidityFractionAfterDeadband = liquidityFractionSigned;
1053+
const deadbandPct = amm.referencePriceOffsetDeadbandPct
1054+
? PERCENTAGE_PRECISION.mul(
1055+
new BN(amm.referencePriceOffsetDeadbandPct as number)
1056+
).divn(100)
1057+
: ZERO;
1058+
if (!liquidityFractionAfterDeadband.eq(ZERO) && deadbandPct.gt(ZERO)) {
1059+
const abs = liquidityFractionAfterDeadband.abs();
1060+
if (abs.lte(deadbandPct)) {
1061+
liquidityFractionAfterDeadband = ZERO;
1062+
} else {
1063+
liquidityFractionAfterDeadband = liquidityFractionAfterDeadband.sub(
1064+
deadbandPct.mul(sigNum(liquidityFractionAfterDeadband))
1065+
);
1066+
}
1067+
}
1068+
10251069
referencePriceOffset = calculateReferencePriceOffset(
10261070
reservePrice,
10271071
amm.last24HAvgFundingRate,
1028-
liquidityFractionSigned,
1072+
liquidityFractionAfterDeadband,
10291073
amm.historicalOracleData.lastOraclePriceTwap5Min,
10301074
amm.lastMarkPriceTwap5Min,
10311075
amm.historicalOracleData.lastOraclePriceTwap,

sdk/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,7 @@ export type AMM = {
11121112
ammInventorySpreadAdjustment: number;
11131113

11141114
lastFundingOracleTwap: BN;
1115+
referencePriceOffsetDeadbandPct: number;
11151116
};
11161117

11171118
// # User Account Types

tests/admin.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,19 @@ describe('admin', () => {
472472
assert(perpMarket.amm.ammSpreadAdjustment == ammSpreadAdjustment);
473473
});
474474

475+
it('update perp market reference offset deadband pct', async () => {
476+
const referenceOffsetDeadbandPct = 5;
477+
await driftClient.updatePerpMarketReferencePriceOffsetDeadbandPct(
478+
0,
479+
referenceOffsetDeadbandPct
480+
);
481+
const perpMarket = driftClient.getPerpMarketAccount(0);
482+
assert(
483+
perpMarket.amm.referencePriceOffsetDeadbandPct ==
484+
referenceOffsetDeadbandPct
485+
);
486+
});
487+
475488
it('update pnl pool', async () => {
476489
const quoteVault = driftClient.getSpotMarketAccount(0).vault;
477490

0 commit comments

Comments
 (0)