Skip to content

Commit

Permalink
bigz/add-isolated-market-to-validate-margin-trading
Browse files Browse the repository at this point in the history
  • Loading branch information
0xbigz committed Mar 13, 2024
1 parent eef66c5 commit 30ece8e
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 16 deletions.
2 changes: 1 addition & 1 deletion programs/drift/src/controller/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3277,7 +3277,7 @@ pub fn place_spot_order(
)?;
}

validate_spot_margin_trading(user, spot_market_map, oracle_map)?;
validate_spot_margin_trading(user, perp_market_map, spot_market_map, oracle_map)?;

Check warning on line 3280 in programs/drift/src/controller/orders.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/controller/orders.rs#L3280

Added line #L3280 was not covered by tests

if force_reduce_only {
validate_order_for_force_reduce_only(
Expand Down
12 changes: 9 additions & 3 deletions programs/drift/src/instructions/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ pub fn handle_withdraw(
MarginRequirementType::Initial,
)?;

validate_spot_margin_trading(user, &spot_market_map, &mut oracle_map)?;
validate_spot_margin_trading(user, &perp_market_map, &spot_market_map, &mut oracle_map)?;

Check warning on line 524 in programs/drift/src/instructions/user.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/user.rs#L524

Added line #L524 was not covered by tests

if user.is_being_liquidated() {
user.exit_liquidation();
Expand Down Expand Up @@ -671,7 +671,12 @@ pub fn handle_transfer_deposit(
MarginRequirementType::Initial,
)?;

validate_spot_margin_trading(from_user, &spot_market_map, &mut oracle_map)?;
validate_spot_margin_trading(
from_user,

Check warning on line 675 in programs/drift/src/instructions/user.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/user.rs#L675

Added line #L675 was not covered by tests
&perp_market_map,
&spot_market_map,
&mut oracle_map,
)?;

if from_user.is_being_liquidated() {
from_user.exit_liquidation();
Expand Down Expand Up @@ -1831,6 +1836,7 @@ pub fn handle_update_user_margin_trading_enabled(
) -> Result<()> {
let remaining_accounts_iter = &mut ctx.remaining_accounts.iter().peekable();
let AccountMaps {
perp_market_map,

Check warning on line 1839 in programs/drift/src/instructions/user.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/user.rs#L1839

Added line #L1839 was not covered by tests
spot_market_map,
mut oracle_map,
..
Expand All @@ -1845,7 +1851,7 @@ pub fn handle_update_user_margin_trading_enabled(
let mut user = load_mut!(ctx.accounts.user)?;
user.is_margin_trading_enabled = margin_trading_enabled;

validate_spot_margin_trading(&user, &spot_market_map, &mut oracle_map)
validate_spot_margin_trading(&user, &perp_market_map, &spot_market_map, &mut oracle_map)

Check warning on line 1854 in programs/drift/src/instructions/user.rs

View check run for this annotation

Codecov / codecov/patch

programs/drift/src/instructions/user.rs#L1854

Added line #L1854 was not covered by tests
.map_err(|_| ErrorCode::MarginOrdersOpen)?;

Ok(())
Expand Down
14 changes: 14 additions & 0 deletions programs/drift/src/math/margin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,7 @@ pub fn calculate_max_withdrawable_amount(

pub fn validate_spot_margin_trading(
user: &User,
perp_market_map: &PerpMarketMap,
spot_market_map: &SpotMarketMap,
oracle_map: &mut OracleMap,
) -> DriftResult {
Expand Down Expand Up @@ -745,6 +746,19 @@ pub fn validate_spot_margin_trading(
}
}

for perp_position in &user.perp_positions {
if perp_position.is_open_position() {
let perp_market = perp_market_map.get_ref(&perp_position.market_index)?;

validate!(
perp_market.contract_tier != ContractTier::Isolated,
ErrorCode::IsolatedAssetTierViolation,
"Isolated perpetual market = {} doesn't allow margin trading",
perp_market.market_index
)?;
}
}

let mut quote_token_amount = 0_i128;
let quote_spot_position = user.get_quote_spot_position();
if !quote_spot_position.is_available() {
Expand Down
171 changes: 159 additions & 12 deletions programs/drift/src/math/margin/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2494,6 +2494,9 @@ mod validate_spot_margin_trading {
use crate::test_utils::get_pyth_price;
use crate::test_utils::*;

use crate::state::perp_market::{ContractTier, MarketStatus, PerpMarket, AMM};
use crate::{AMM_RESERVE_PRECISION, BASE_PRECISION_I64, PEG_PRECISION, QUOTE_PRECISION_I64};

#[test]
pub fn sol_ask_larger_than_deposit() {
let slot = 0_u64;
Expand All @@ -2510,7 +2513,7 @@ mod validate_spot_margin_trading {
);
let mut oracle_map = OracleMap::load_one(&oracle_account_info, slot, None).unwrap();

let _market_map = PerpMarketMap::empty();
let perp_market_map = PerpMarketMap::empty();

let mut usdc_spot_market = SpotMarket {
market_index: 0,
Expand Down Expand Up @@ -2567,7 +2570,12 @@ mod validate_spot_margin_trading {
..User::default()
};

let result = validate_spot_margin_trading(&user, &spot_market_map, &mut oracle_map);
let result = validate_spot_margin_trading(
&user,
&perp_market_map,
&spot_market_map,
&mut oracle_map,
);

assert_eq!(result, Err(ErrorCode::MarginTradingDisabled));
}
Expand All @@ -2588,7 +2596,7 @@ mod validate_spot_margin_trading {
);
let mut oracle_map = OracleMap::load_one(&oracle_account_info, slot, None).unwrap();

let _market_map = PerpMarketMap::empty();
let perp_market_map = PerpMarketMap::empty();

let mut usdc_spot_market = SpotMarket {
market_index: 0,
Expand Down Expand Up @@ -2645,7 +2653,12 @@ mod validate_spot_margin_trading {
..User::default()
};

let result = validate_spot_margin_trading(&user, &spot_market_map, &mut oracle_map);
let result = validate_spot_margin_trading(
&user,
&perp_market_map,
&spot_market_map,
&mut oracle_map,
);

assert_eq!(result, Ok(()));
}
Expand All @@ -2666,7 +2679,7 @@ mod validate_spot_margin_trading {
);
let mut oracle_map = OracleMap::load_one(&oracle_account_info, slot, None).unwrap();

let _market_map = PerpMarketMap::empty();
let perp_market_map = PerpMarketMap::empty();

let mut usdc_spot_market = SpotMarket {
market_index: 0,
Expand Down Expand Up @@ -2723,7 +2736,12 @@ mod validate_spot_margin_trading {
..User::default()
};

let result = validate_spot_margin_trading(&user, &spot_market_map, &mut oracle_map);
let result = validate_spot_margin_trading(
&user,
&perp_market_map,
&spot_market_map,
&mut oracle_map,
);

assert_eq!(result, Err(ErrorCode::MarginTradingDisabled));
}
Expand All @@ -2744,7 +2762,7 @@ mod validate_spot_margin_trading {
);
let mut oracle_map = OracleMap::load_one(&oracle_account_info, slot, None).unwrap();

let _market_map = PerpMarketMap::empty();
let perp_market_map = PerpMarketMap::empty();

let mut usdc_spot_market = SpotMarket {
market_index: 0,
Expand Down Expand Up @@ -2801,7 +2819,12 @@ mod validate_spot_margin_trading {
..User::default()
};

let result = validate_spot_margin_trading(&user, &spot_market_map, &mut oracle_map);
let result = validate_spot_margin_trading(
&user,
&perp_market_map,
&spot_market_map,
&mut oracle_map,
);

assert_eq!(result, Err(ErrorCode::MarginTradingDisabled));
}
Expand All @@ -2822,7 +2845,7 @@ mod validate_spot_margin_trading {
);
let mut oracle_map = OracleMap::load_one(&oracle_account_info, slot, None).unwrap();

let _market_map = PerpMarketMap::empty();
let perp_market_map = PerpMarketMap::empty();

let mut usdc_spot_market = SpotMarket {
market_index: 0,
Expand Down Expand Up @@ -2879,7 +2902,12 @@ mod validate_spot_margin_trading {
..User::default()
};

let result = validate_spot_margin_trading(&user, &spot_market_map, &mut oracle_map);
let result = validate_spot_margin_trading(
&user,
&perp_market_map,
&spot_market_map,
&mut oracle_map,
);

assert_eq!(result, Ok(()));
}
Expand All @@ -2900,7 +2928,7 @@ mod validate_spot_margin_trading {
);
let mut oracle_map = OracleMap::load_one(&oracle_account_info, slot, None).unwrap();

let _market_map = PerpMarketMap::empty();
let perp_market_map = PerpMarketMap::empty();

let mut usdc_spot_market = SpotMarket {
market_index: 0,
Expand Down Expand Up @@ -2957,10 +2985,129 @@ mod validate_spot_margin_trading {
..User::default()
};

let result = validate_spot_margin_trading(&user, &spot_market_map, &mut oracle_map);
let result = validate_spot_margin_trading(
&user,
&perp_market_map,
&spot_market_map,
&mut oracle_map,
);

assert_eq!(result, Err(ErrorCode::MarginTradingDisabled));
}

#[test]
pub fn attempt_enable_margin_trading_with_isolated_perp() {
let slot = 0_u64;

let mut sol_oracle_price = get_pyth_price(100, 6);
let sol_oracle_price_key =
Pubkey::from_str("J83w4HKfqxwcq3BEMMkPFSppX3gqekLyLJBexebFVkix").unwrap();
let pyth_program = crate::ids::pyth_program::id();
create_account_info!(
sol_oracle_price,
&sol_oracle_price_key,
&pyth_program,
oracle_account_info
);
let mut oracle_map = OracleMap::load_one(&oracle_account_info, slot, None).unwrap();

let mut market = PerpMarket {
amm: AMM {
base_asset_reserve: 100 * AMM_RESERVE_PRECISION,
quote_asset_reserve: 100 * AMM_RESERVE_PRECISION,
bid_base_asset_reserve: 101 * AMM_RESERVE_PRECISION,
bid_quote_asset_reserve: 99 * AMM_RESERVE_PRECISION,
ask_base_asset_reserve: 99 * AMM_RESERVE_PRECISION,
ask_quote_asset_reserve: 101 * AMM_RESERVE_PRECISION,
sqrt_k: 100 * AMM_RESERVE_PRECISION,
peg_multiplier: 100 * PEG_PRECISION,
order_step_size: 10000000,
oracle: sol_oracle_price_key,
..AMM::default()
},
margin_ratio_initial: 1000,
margin_ratio_maintenance: 500,
status: MarketStatus::Initialized,
contract_tier: ContractTier::Isolated,

..PerpMarket::default()
};
create_anchor_account_info!(market, PerpMarket, market_account_info);
let perp_market_map = PerpMarketMap::load_one(&market_account_info, true).unwrap();

let mut usdc_spot_market = SpotMarket {
market_index: 0,
oracle_source: OracleSource::QuoteAsset,
cumulative_deposit_interest: SPOT_CUMULATIVE_INTEREST_PRECISION,
decimals: 6,
initial_asset_weight: SPOT_WEIGHT_PRECISION,
maintenance_asset_weight: SPOT_WEIGHT_PRECISION,
deposit_balance: 10000 * SPOT_BALANCE_PRECISION,
liquidator_fee: 0,
..SpotMarket::default()
};
create_anchor_account_info!(usdc_spot_market, SpotMarket, usdc_spot_market_account_info);
let mut sol_spot_market = SpotMarket {
market_index: 1,
oracle_source: OracleSource::Pyth,
oracle: sol_oracle_price_key,
cumulative_deposit_interest: SPOT_CUMULATIVE_INTEREST_PRECISION,
cumulative_borrow_interest: SPOT_CUMULATIVE_INTEREST_PRECISION,
decimals: 9,
initial_asset_weight: 8 * SPOT_WEIGHT_PRECISION / 10,
maintenance_asset_weight: 9 * SPOT_WEIGHT_PRECISION / 10,
initial_liability_weight: 12 * SPOT_WEIGHT_PRECISION / 10,
maintenance_liability_weight: 11 * SPOT_WEIGHT_PRECISION / 10,
liquidator_fee: LIQUIDATION_FEE_PRECISION / 1000,
..SpotMarket::default()
};
create_anchor_account_info!(sol_spot_market, SpotMarket, sol_spot_market_account_info);
let spot_market_account_infos = Vec::from([
&usdc_spot_market_account_info,
&sol_spot_market_account_info,
]);
let spot_market_map =
SpotMarketMap::load_multiple(spot_market_account_infos, true).unwrap();

let mut spot_positions = [SpotPosition::default(); 8];
spot_positions[0] = SpotPosition {
market_index: 0,
balance_type: SpotBalanceType::Deposit,
scaled_balance: 100 * SPOT_BALANCE_PRECISION_U64,
..SpotPosition::default()
};
spot_positions[1] = SpotPosition {
market_index: 1,
balance_type: SpotBalanceType::Deposit,
scaled_balance: 2 * SPOT_BALANCE_PRECISION_U64,
open_bids: 2 * 10_i64.pow(9),
..SpotPosition::default()
};
let user = User {
orders: [Order::default(); 32],
perp_positions: get_positions(PerpPosition {
market_index: 0,
base_asset_amount: BASE_PRECISION_I64,
quote_asset_amount: -150 * QUOTE_PRECISION_I64,
quote_entry_amount: -150 * QUOTE_PRECISION_I64,
quote_break_even_amount: -150 * QUOTE_PRECISION_I64,
open_orders: 1,
open_bids: BASE_PRECISION_I64,
..PerpPosition::default()
}),
spot_positions,
..User::default()
};

let result = validate_spot_margin_trading(
&user,
&perp_market_map,
&spot_market_map,
&mut oracle_map,
);

assert_eq!(result, Err(ErrorCode::IsolatedAssetTierViolation));
}
}

#[cfg(test)]
Expand Down

0 comments on commit 30ece8e

Please sign in to comment.