Skip to content

Commit b2f3d7e

Browse files
moosecat2jordy25519
authored andcommitted
Nour/validate fill change (#1772)
* program: new amm oracle (#1738) * zero unused amm fields * cargo fmt * bare bones ix * minimal anchor mm oracle impl * update test file * only do admin validate when not anchor test * updates * generalize native entry * fix weird function name chop off * make it compile for --feature cpi (#1748) Co-authored-by: jordy25519 <[email protected]> * more efficeint clock and state bit flags check * vamm uses mm oracle (#1747) * add offset * working tests * refactor to use MM oracle as its own type * remove weird preface * sdk updates * bankrun tests all pass * fix test * changes and fixes * widen confidence if mm oracle too diff * sdk side for confidence adjust * changelog * fix lint * fix cargo tests * address comments * add conf check * remove anchor ix and cache oracle confidence * only state admin can reenable mm oracle kill switch * cargo fmt --------- Co-authored-by: jordy25519 <[email protected]> * fix tests (#1764) * Nour/move ixs around (#1766) * move around ixs * remove message * add devnet oracle crank wallet * refactored mm oracle * sdk changes + cargo fmt * fix tests * validate price bands with fill fix * normalize fill within price bands * add sdk warning * updated type * undefined guard so anchor tests pass * accept vec for update amm and view amm * adjust test to work with new price bands * Revert "adjust test to work with new price bands" This reverts commit ee40ac8. * remove price bands logic * add zero ix for mm oracle for reset * v1 safety improvements * isolate funding from MM oracle * add cargo tests for amm availability * change oracle validity log bool to enum * address comment * make validate fill direction agnostic * fix liquidate borrow for perp pnl test * fix tests and address comments --------- Co-authored-by: jordy25519 <[email protected]>
1 parent cb1e7df commit b2f3d7e

File tree

9 files changed

+134
-114
lines changed

9 files changed

+134
-114
lines changed

programs/drift/src/controller/orders.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,7 +1327,6 @@ pub fn fill_perp_order(
13271327
let perp_market = perp_market_map.get_ref(&market_index)?;
13281328
validate_fill_price_within_price_bands(
13291329
fill_price,
1330-
order_direction,
13311330
oracle_price,
13321331
oracle_twap_5min,
13331332
perp_market.margin_ratio_initial,
@@ -4090,7 +4089,6 @@ pub fn fill_spot_order(
40904089
.last_oracle_price_twap_5min;
40914090
validate_fill_price_within_price_bands(
40924091
fill_price,
4093-
order_direction,
40944092
oracle_price,
40954093
oracle_twap_5min,
40964094
spot_market.get_margin_ratio(&MarginRequirementType::Initial)?,

programs/drift/src/math/orders.rs

Lines changed: 38 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::cmp::min;
22
use std::ops::Sub;
33

4+
use crate::math::constants::PERCENTAGE_PRECISION;
5+
use crate::math::constants::PERCENTAGE_PRECISION_I128;
46
use crate::msg;
57

68
use crate::controller::position::PositionDelta;
@@ -11,10 +13,10 @@ use crate::math::casting::Cast;
1113
use crate::state::protected_maker_mode_config::ProtectedMakerParams;
1214
use crate::state::user::OrderBitFlag;
1315
use crate::{
14-
load, math, FeeTier, State, BASE_PRECISION_I128, FEE_ADJUSTMENT_MAX, MARGIN_PRECISION_I128,
16+
load, math, FeeTier, BASE_PRECISION_I128, FEE_ADJUSTMENT_MAX, MARGIN_PRECISION_I128,
1517
MAX_PREDICTION_MARKET_PRICE, MAX_PREDICTION_MARKET_PRICE_I64, OPEN_ORDER_MARGIN_REQUIREMENT,
16-
PERCENTAGE_PRECISION, PERCENTAGE_PRECISION_U64, PRICE_PRECISION_I128, PRICE_PRECISION_U64,
17-
QUOTE_PRECISION_I128, SPOT_WEIGHT_PRECISION, SPOT_WEIGHT_PRECISION_I128,
18+
PERCENTAGE_PRECISION_U64, PRICE_PRECISION_I128, PRICE_PRECISION_U64, QUOTE_PRECISION_I128,
19+
SPOT_WEIGHT_PRECISION, SPOT_WEIGHT_PRECISION_I128,
1820
};
1921

2022
use crate::math::constants::MARGIN_PRECISION_U128;
@@ -484,7 +486,6 @@ pub fn limit_price_breaches_maker_oracle_price_bands(
484486

485487
pub fn validate_fill_price_within_price_bands(
486488
fill_price: u64,
487-
direction: PositionDirection,
488489
oracle_price: i64,
489490
oracle_twap_5min: i64,
490491
margin_ratio_initial: u32,
@@ -503,85 +504,44 @@ pub fn validate_fill_price_within_price_bands(
503504
return Ok(());
504505
}
505506

506-
let oracle_price = oracle_price.unsigned_abs();
507-
let oracle_twap_5min = oracle_twap_5min.unsigned_abs();
508-
509507
let max_oracle_diff = margin_ratio_initial.cast::<u128>()?;
510508
let max_oracle_twap_diff = oracle_twap_5min_percent_divergence.cast::<u128>()?; // 50%
511509

512-
if direction == PositionDirection::Long {
513-
if fill_price < oracle_price && fill_price < oracle_twap_5min {
514-
return Ok(());
515-
}
516-
517-
let percent_diff: u128 = fill_price
518-
.saturating_sub(oracle_price)
519-
.cast::<u128>()?
520-
.safe_mul(MARGIN_PRECISION_U128)?
521-
.safe_div(oracle_price.cast()?)?;
522-
523-
validate!(
524-
percent_diff < max_oracle_diff,
525-
ErrorCode::PriceBandsBreached,
526-
"Fill Price Breaches Oracle Price Bands: {} % <= {} % (fill: {} >= oracle: {})",
527-
max_oracle_diff,
528-
percent_diff,
529-
fill_price,
530-
oracle_price
531-
)?;
532-
533-
let percent_diff = fill_price
534-
.saturating_sub(oracle_twap_5min)
535-
.cast::<u128>()?
536-
.safe_mul(PERCENTAGE_PRECISION)?
537-
.safe_div(oracle_twap_5min.cast()?)?;
538-
539-
validate!(
540-
percent_diff < max_oracle_twap_diff,
541-
ErrorCode::PriceBandsBreached,
542-
"Fill Price Breaches Oracle TWAP Price Bands: {} % <= {} % (fill: {} >= twap: {})",
543-
max_oracle_twap_diff,
544-
percent_diff,
545-
fill_price,
546-
oracle_twap_5min
547-
)?;
548-
} else {
549-
if fill_price > oracle_price && fill_price > oracle_twap_5min {
550-
return Ok(());
551-
}
552-
553-
let percent_diff: u128 = oracle_price
554-
.saturating_sub(fill_price)
555-
.cast::<u128>()?
556-
.safe_mul(MARGIN_PRECISION_U128)?
557-
.safe_div(oracle_price.cast()?)?;
558-
559-
validate!(
560-
percent_diff < max_oracle_diff,
561-
ErrorCode::PriceBandsBreached,
562-
"Fill Price Breaches Oracle Price Bands: {} % <= {} % (fill: {} <= oracle: {})",
563-
max_oracle_diff,
564-
percent_diff,
565-
fill_price,
566-
oracle_price
567-
)?;
510+
let percent_diff = fill_price
511+
.cast::<i64>()?
512+
.safe_sub(oracle_price)?
513+
.cast::<i128>()?
514+
.safe_mul(MARGIN_PRECISION_I128)?
515+
.safe_div(oracle_price.cast::<i128>()?)?
516+
.unsigned_abs();
568517

569-
let percent_diff = oracle_twap_5min
570-
.saturating_sub(fill_price)
571-
.cast::<u128>()?
572-
.safe_mul(PERCENTAGE_PRECISION)?
573-
.safe_div(oracle_twap_5min.cast()?)?;
518+
let percent_diff_twap = fill_price
519+
.cast::<i64>()?
520+
.safe_sub(oracle_twap_5min)?
521+
.cast::<i128>()?
522+
.safe_mul(PERCENTAGE_PRECISION_I128)?
523+
.safe_div(oracle_twap_5min.cast::<i128>()?)?
524+
.unsigned_abs();
525+
526+
validate!(
527+
percent_diff < max_oracle_diff,
528+
ErrorCode::PriceBandsBreached,
529+
"Fill Price Breaches Oracle Price Bands: max_oracle_diff {} % , pct diff {} % (fill: {} , oracle: {})",
530+
max_oracle_diff,
531+
percent_diff,
532+
fill_price,
533+
oracle_price
534+
)?;
574535

575-
validate!(
576-
percent_diff < max_oracle_twap_diff,
577-
ErrorCode::PriceBandsBreached,
578-
"Fill Price Breaches Oracle TWAP Price Bands: {} % <= {} % (fill: {} <= twap: {})",
579-
max_oracle_twap_diff,
580-
percent_diff,
581-
fill_price,
582-
oracle_twap_5min
583-
)?;
584-
}
536+
validate!(
537+
percent_diff_twap < max_oracle_twap_diff,
538+
ErrorCode::PriceBandsBreached,
539+
"Fill Price Breaches Oracle TWAP Price Bands: max_oracle_twap_diff {} % , pct diff {} % (fill: {} , twap: {})",
540+
max_oracle_twap_diff,
541+
percent_diff,
542+
fill_price,
543+
oracle_twap_5min
544+
)?;
585545

586546
Ok(())
587547
}

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

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3161,22 +3161,17 @@ mod calculate_max_perp_order_size {
31613161

31623162
pub mod validate_fill_price_within_price_bands {
31633163
use crate::math::orders::validate_fill_price_within_price_bands;
3164-
use crate::{
3165-
PositionDirection, MARGIN_PRECISION, PERCENTAGE_PRECISION, PRICE_PRECISION_I64,
3166-
PRICE_PRECISION_U64,
3167-
};
3164+
use crate::{MARGIN_PRECISION, PERCENTAGE_PRECISION, PRICE_PRECISION_I64, PRICE_PRECISION_U64};
31683165

31693166
#[test]
31703167
fn valid_long() {
31713168
let oracle_price = 100 * PRICE_PRECISION_I64;
31723169
let twap = oracle_price;
31733170
let fill_price = 105 * PRICE_PRECISION_U64;
3174-
let direction = PositionDirection::Long;
31753171
let margin_ratio_initial = MARGIN_PRECISION / 10;
31763172

31773173
assert!(validate_fill_price_within_price_bands(
31783174
fill_price,
3179-
direction,
31803175
oracle_price,
31813176
twap,
31823177
margin_ratio_initial,
@@ -3191,12 +3186,10 @@ pub mod validate_fill_price_within_price_bands {
31913186
let oracle_price = 100 * PRICE_PRECISION_I64;
31923187
let twap = oracle_price;
31933188
let fill_price = 95 * PRICE_PRECISION_U64;
3194-
let direction = PositionDirection::Short;
31953189
let margin_ratio_initial = MARGIN_PRECISION / 10;
31963190

31973191
assert!(validate_fill_price_within_price_bands(
31983192
fill_price,
3199-
direction,
32003193
oracle_price,
32013194
twap,
32023195
margin_ratio_initial,
@@ -3212,12 +3205,10 @@ pub mod validate_fill_price_within_price_bands {
32123205
let twap = oracle_price;
32133206
// 11% greater than oracle price
32143207
let fill_price = 111 * PRICE_PRECISION_U64;
3215-
let direction = PositionDirection::Long;
32163208
let margin_ratio_initial = MARGIN_PRECISION / 10; // 10x
32173209

32183210
assert!(validate_fill_price_within_price_bands(
32193211
fill_price,
3220-
direction,
32213212
oracle_price,
32223213
twap,
32233214
margin_ratio_initial,
@@ -3233,12 +3224,10 @@ pub mod validate_fill_price_within_price_bands {
32333224
let twap = oracle_price;
32343225
// 11% less than oracle price
32353226
let fill_price = 89 * PRICE_PRECISION_U64;
3236-
let direction = PositionDirection::Short;
32373227
let margin_ratio_initial = MARGIN_PRECISION / 10; // 10x
32383228

32393229
assert!(validate_fill_price_within_price_bands(
32403230
fill_price,
3241-
direction,
32423231
oracle_price,
32433232
twap,
32443233
margin_ratio_initial,
@@ -3254,12 +3243,10 @@ pub mod validate_fill_price_within_price_bands {
32543243
let twap = 100 * PRICE_PRECISION_I64;
32553244
// 50% greater than twap
32563245
let fill_price = 150 * PRICE_PRECISION_U64;
3257-
let direction = PositionDirection::Long;
32583246
let margin_ratio_initial = MARGIN_PRECISION / 10; // 10x
32593247

32603248
assert!(validate_fill_price_within_price_bands(
32613249
fill_price,
3262-
direction,
32633250
oracle_price,
32643251
twap,
32653252
margin_ratio_initial,
@@ -3275,12 +3262,48 @@ pub mod validate_fill_price_within_price_bands {
32753262
let twap = 100 * PRICE_PRECISION_I64;
32763263
// 50% less than twap
32773264
let fill_price = 50 * PRICE_PRECISION_U64;
3278-
let direction = PositionDirection::Short;
32793265
let margin_ratio_initial = MARGIN_PRECISION / 10; // 10x
32803266

32813267
assert!(validate_fill_price_within_price_bands(
32823268
fill_price,
3283-
direction,
3269+
oracle_price,
3270+
twap,
3271+
margin_ratio_initial,
3272+
(PERCENTAGE_PRECISION / 2) as u64,
3273+
false,
3274+
)
3275+
.is_err())
3276+
}
3277+
3278+
#[test]
3279+
fn invalid_volatile_taker_long() {
3280+
let oracle_price = 50 * PRICE_PRECISION_I64;
3281+
let twap = 100 * PRICE_PRECISION_I64;
3282+
// 50% less than twap
3283+
let fill_price = 1 * PRICE_PRECISION_U64;
3284+
let margin_ratio_initial = MARGIN_PRECISION / 10; // 10x
3285+
3286+
assert!(validate_fill_price_within_price_bands(
3287+
fill_price,
3288+
oracle_price,
3289+
twap,
3290+
margin_ratio_initial,
3291+
(PERCENTAGE_PRECISION / 2) as u64,
3292+
false,
3293+
)
3294+
.is_err())
3295+
}
3296+
3297+
#[test]
3298+
fn invalid_volatile_taker_short() {
3299+
let oracle_price = 50 * PRICE_PRECISION_I64;
3300+
let twap = 100 * PRICE_PRECISION_I64;
3301+
// 50% less than twap
3302+
let fill_price = 200 * PRICE_PRECISION_U64;
3303+
let margin_ratio_initial = MARGIN_PRECISION / 10; // 10x
3304+
3305+
assert!(validate_fill_price_within_price_bands(
3306+
fill_price,
32843307
oracle_price,
32853308
twap,
32863309
margin_ratio_initial,

programs/drift/src/math/spot_swap.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ pub fn validate_price_bands_for_swap(
100100
out_price: i64,
101101
oracle_twap_5min_percent_divergence: u64,
102102
) -> DriftResult {
103-
let (fill_price, direction, oracle_price, oracle_twap_5min, margin_ratio) = {
103+
let (fill_price, oracle_price, oracle_twap_5min, margin_ratio) = {
104104
let in_market_margin_ratio = in_market.get_margin_ratio(&MarginRequirementType::Initial)?;
105105

106106
if in_market_margin_ratio != 0 {
@@ -113,7 +113,6 @@ pub fn validate_price_bands_for_swap(
113113

114114
(
115115
fill_price,
116-
PositionDirection::Short,
117116
in_price,
118117
in_market.historical_oracle_data.last_oracle_price_twap_5min,
119118
in_market_margin_ratio,
@@ -124,7 +123,6 @@ pub fn validate_price_bands_for_swap(
124123

125124
(
126125
fill_price,
127-
PositionDirection::Long,
128126
out_price,
129127
out_market
130128
.historical_oracle_data
@@ -136,7 +134,6 @@ pub fn validate_price_bands_for_swap(
136134

137135
validate_fill_price_within_price_bands(
138136
fill_price,
139-
direction,
140137
oracle_price,
141138
oracle_twap_5min,
142139
margin_ratio,

sdk/src/idl/drift.json

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2099,7 +2099,12 @@
20992099
"isSigner": false
21002100
}
21012101
],
2102-
"args": []
2102+
"args": [
2103+
{
2104+
"name": "disableMaintenance",
2105+
"type": "bool"
2106+
}
2107+
]
21032108
},
21042109
{
21052110
"name": "updateUserFuelBonus",
@@ -7795,11 +7800,24 @@
77957800
"type": "u8"
77967801
},
77977802
{
7798-
"name": "padding",
7803+
"name": "padding1",
77997804
"type": {
78007805
"array": [
78017806
"u8",
7802-
31
7807+
3
7808+
]
7809+
}
7810+
},
7811+
{
7812+
"name": "currentMaintenanceUsers",
7813+
"type": "u32"
7814+
},
7815+
{
7816+
"name": "padding2",
7817+
"type": {
7818+
"array": [
7819+
"u8",
7820+
24
78037821
]
78047822
}
78057823
}
@@ -12002,6 +12020,26 @@
1200212020
]
1200312021
}
1200412022
},
12023+
{
12024+
"name": "LogMode",
12025+
"type": {
12026+
"kind": "enum",
12027+
"variants": [
12028+
{
12029+
"name": "None"
12030+
},
12031+
{
12032+
"name": "ExchangeOracle"
12033+
},
12034+
{
12035+
"name": "MMOracle"
12036+
},
12037+
{
12038+
"name": "SafeMMOracle"
12039+
}
12040+
]
12041+
}
12042+
},
1200512043
{
1200612044
"name": "PositionUpdateType",
1200712045
"type": {

0 commit comments

Comments
 (0)