Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

program: scale down init asset weights past threshold #575

Merged
merged 43 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
1419196
initial logic to scale initial weight
crispheaney Aug 12, 2023
3410cbe
add cargo test
crispheaney Aug 12, 2023
a07aaa6
add initial sdk logic
crispheaney Aug 12, 2023
4216eed
tweak field comments
crispheaney Aug 24, 2023
b50079a
program: add twap to initial asset weight calc
crispheaney Aug 24, 2023
7710759
inital work for worst case to account for free collateral contribution
crispheaney Aug 24, 2023
44ff8fa
add strict oracle price
crispheaney Aug 24, 2023
b9bc2d3
tests work
crispheaney Aug 25, 2023
4c0a440
used cache values from calc worst case token amounts
crispheaney Aug 25, 2023
37fc067
rm comment
crispheaney Aug 25, 2023
b1d271c
use free collateral contribution in place_spot_order
crispheaney Aug 25, 2023
693b1d8
use strict quote in calculate_perp_position_value_and_pnl
crispheaney Aug 25, 2023
093dd65
remove w bounds from pnl calc
crispheaney Aug 25, 2023
571471e
expand worst case tests
crispheaney Aug 25, 2023
eb1e0df
test the twap logic in worst case calc
crispheaney Aug 26, 2023
d04b263
some simplifications
crispheaney Aug 26, 2023
471be94
add some tests for scaled asset weight using twap
crispheaney Aug 26, 2023
59a206e
make calc max spot order size work
crispheaney Aug 28, 2023
4a9eb51
tweak place_spot_order on how it checks if spot order is risk decreasing
crispheaney Aug 28, 2023
bcd3224
Merge branch 'master' into crispheaney/scale-asset-weight
crispheaney Aug 29, 2023
3ccdbb0
always do margin check in place order
crispheaney Aug 29, 2023
f24c7bf
log margin type in meets_place_order_margin_requirement
crispheaney Aug 29, 2023
ebc003a
fix a bug
crispheaney Aug 29, 2023
27c6e20
better logic for deciding if trigger order is risk increasing
crispheaney Aug 29, 2023
b861927
sdk: rework calculateWorstCaseTokenAmounts
crispheaney Aug 30, 2023
a655af2
place order params keep track of risk increasing
crispheaney Aug 30, 2023
1ba66a6
tweaks
crispheaney Aug 30, 2023
22d3396
tweak some tests
crispheaney Aug 30, 2023
40e735d
add some comments
crispheaney Aug 30, 2023
2289506
tweak some tests
crispheaney Aug 30, 2023
57c3616
calculate_max_withdrawable_amount use spot_market.get_asset_weight
crispheaney Aug 30, 2023
a95bd83
fix ts tests
crispheaney Aug 30, 2023
80b5205
get_asset_weight just takes oracle price
crispheaney Aug 30, 2023
1404cb4
calculateAssetWeight doesn't look at twap
crispheaney Aug 30, 2023
65339a3
add strictOraclePrice
crispheaney Aug 30, 2023
3cb63d6
add strictOraclePrice
crispheaney Aug 30, 2023
c37b85e
add some sdk tests for worst case token amount calc
crispheaney Aug 30, 2023
32b69b4
Merge branch 'master' into crispheaney/scale-asset-weight
crispheaney Aug 30, 2023
b7fd7ba
add is riskier logic to OrderFillSimulation
crispheaney Sep 5, 2023
ccceb9c
tweak to sdk
crispheaney Sep 5, 2023
83e13d1
Merge branch 'master' into crispheaney/scale-asset-weight
crispheaney Sep 6, 2023
2a4b71f
add admin function to update scaleInitialAssetWeightStart
crispheaney Sep 6, 2023
a4669a4
CHANGELOG
crispheaney Sep 6, 2023
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
3 changes: 2 additions & 1 deletion programs/drift/src/instructions/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,8 @@ pub fn handle_initialize_spot_market(
flash_loan_amount: 0,
flash_loan_initial_token_amount: 0,
total_swap_fee: 0,
padding: [0; 56],
scale_initial_asset_weight_start: 0,
padding: [0; 48],
insurance_fund: InsuranceFund {
vault: *ctx.accounts.insurance_fund_vault.to_account_info().key,
unstaking_period: THIRTEEN_DAY,
Expand Down
1 change: 1 addition & 0 deletions programs/drift/src/math/margin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ pub fn calculate_margin_requirement_and_total_collateral_and_liability_info(
spot_market
.get_asset_weight(
worst_case_token_amount.unsigned_abs(),
oracle_price_data.price,
&margin_requirement_type,
)?
.cast()?,
Expand Down
58 changes: 53 additions & 5 deletions programs/drift/src/math/margin/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ mod test {
use crate::state::perp_market::{ContractTier, PerpMarket, AMM};
use crate::state::spot_market::{AssetTier, SpotMarket};
use crate::state::user::PerpPosition;
use crate::{
PRICE_PRECISION_I64, QUOTE_PRECISION_U64, SPOT_BALANCE_PRECISION,
SPOT_CUMULATIVE_INTEREST_PRECISION,
};

#[test]
fn asset_tier_checks() {
Expand Down Expand Up @@ -80,8 +84,9 @@ mod test {
};

let size = 1000 * QUOTE_PRECISION;
let price = QUOTE_PRECISION_I64;
let asset_weight = spot_market
.get_asset_weight(size, &MarginRequirementType::Initial)
.get_asset_weight(size, price, &MarginRequirementType::Initial)
.unwrap();
assert_eq!(asset_weight, 9000);

Expand All @@ -92,7 +97,7 @@ mod test {

spot_market.imf_factor = 10;
let asset_weight = spot_market
.get_asset_weight(size, &MarginRequirementType::Initial)
.get_asset_weight(size, price, &MarginRequirementType::Initial)
.unwrap();
assert_eq!(asset_weight, 9000);

Expand All @@ -103,13 +108,13 @@ mod test {

let same_asset_weight_diff_imf_factor = 8357;
let asset_weight = spot_market
.get_asset_weight(size * 1_000_000, &MarginRequirementType::Initial)
.get_asset_weight(size * 1_000_000, price, &MarginRequirementType::Initial)
.unwrap();
assert_eq!(asset_weight, same_asset_weight_diff_imf_factor);

spot_market.imf_factor = 10000;
let asset_weight = spot_market
.get_asset_weight(size, &MarginRequirementType::Initial)
.get_asset_weight(size, price, &MarginRequirementType::Initial)
.unwrap();
assert_eq!(asset_weight, same_asset_weight_diff_imf_factor);

Expand All @@ -120,7 +125,7 @@ mod test {

spot_market.imf_factor = SPOT_IMF_PRECISION / 10;
let asset_weight = spot_market
.get_asset_weight(size, &MarginRequirementType::Initial)
.get_asset_weight(size, price, &MarginRequirementType::Initial)
.unwrap();
assert_eq!(asset_weight, 2642);

Expand All @@ -135,6 +140,49 @@ mod test {
assert_eq!(maint_lib_weight, 31622);
}

#[test]
fn spot_market_scale_initial_asset_weight() {
let mut sol_spot_market = SpotMarket {
initial_asset_weight: 9000,
initial_liability_weight: 11000,
decimals: 9,
imf_factor: 0,
scale_initial_asset_weight_start: 500_000 * QUOTE_PRECISION_U64,
cumulative_deposit_interest: SPOT_CUMULATIVE_INTEREST_PRECISION,
..SpotMarket::default()
};

let price = 25 * PRICE_PRECISION_I64;

sol_spot_market.deposit_balance = SPOT_BALANCE_PRECISION;
let asset_weight = sol_spot_market
.get_scaled_initial_asset_weight(price)
.unwrap();

assert_eq!(asset_weight, 9000);

sol_spot_market.deposit_balance = 20000 * SPOT_BALANCE_PRECISION;
let asset_weight = sol_spot_market
.get_scaled_initial_asset_weight(price)
.unwrap();

assert_eq!(asset_weight, 9000);

sol_spot_market.deposit_balance = 40000 * SPOT_BALANCE_PRECISION;
let asset_weight = sol_spot_market
.get_scaled_initial_asset_weight(price)
.unwrap();

assert_eq!(asset_weight, 4500);

sol_spot_market.deposit_balance = 60000 * SPOT_BALANCE_PRECISION;
let asset_weight = sol_spot_market
.get_scaled_initial_asset_weight(price)
.unwrap();

assert_eq!(asset_weight, 3000);
}

#[test]
fn calculate_user_equity_value_tests() {
let mut market = PerpMarket {
Expand Down
14 changes: 10 additions & 4 deletions programs/drift/src/math/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,7 @@ pub fn calculate_max_spot_order_size(

let asset_weight = spot_market.get_asset_weight(
worst_case_token_amount.unsigned_abs(),
oracle_price_data.price,
&MarginRequirementType::Initial,
)?;

Expand All @@ -1075,6 +1076,7 @@ pub fn calculate_max_spot_order_size(
} else if worst_case_token_amount > 0 && direction == PositionDirection::Short {
let asset_weight = spot_market.get_asset_weight(
worst_case_token_amount.unsigned_abs(),
oracle_price_data.price,
&MarginRequirementType::Initial,
)?;

Expand Down Expand Up @@ -1132,6 +1134,7 @@ pub fn calculate_max_spot_order_size(
let free_collateral_delta = calculate_free_collateral_delta_for_spot(
&spot_market,
worst_case_token_amount.unsigned_abs(),
oracle_price_data.price,
direction,
)?;

Expand All @@ -1153,6 +1156,7 @@ pub fn calculate_max_spot_order_size(
worst_case_token_amount
.unsigned_abs()
.safe_add(order_size.cast()?)?,
oracle_price_data.price,
direction,
)?;

Expand All @@ -1176,13 +1180,15 @@ pub fn calculate_max_spot_order_size(
fn calculate_free_collateral_delta_for_spot(
spot_market: &SpotMarket,
worst_case_token_amount: u128,
oracle_price: i64,
order_direction: PositionDirection,
) -> DriftResult<u32> {
Ok(if order_direction == PositionDirection::Long {
SPOT_WEIGHT_PRECISION.sub(
spot_market
.get_asset_weight(worst_case_token_amount, &MarginRequirementType::Initial)?,
)
SPOT_WEIGHT_PRECISION.sub(spot_market.get_asset_weight(
worst_case_token_amount,
oracle_price,
&MarginRequirementType::Initial,
)?)
} else {
spot_market
.get_liability_weight(worst_case_token_amount, &MarginRequirementType::Initial)?
Expand Down
1 change: 1 addition & 0 deletions programs/drift/src/math/spot_swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub fn select_margin_type_for_swap(
let weight = if token_amount >= 0 {
market.get_asset_weight(
token_amount.unsigned_abs(),
price,
&MarginRequirementType::Initial,
)?
} else {
Expand Down
36 changes: 32 additions & 4 deletions programs/drift/src/state/spot_market.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::math::margin::{
MarginRequirementType,
};
use crate::math::safe_math::SafeMath;
use crate::math::spot_balance::{calculate_utilization, get_token_amount};
use crate::math::spot_balance::{calculate_utilization, get_token_amount, get_token_value};

use crate::state::oracle::{HistoricalIndexData, HistoricalOracleData, OracleSource};
use crate::state::perp_market::{MarketStatus, PoolBalance};
Expand Down Expand Up @@ -167,7 +167,9 @@ pub struct SpotMarket {
/// The total fees received from swaps
/// precision: token mint precision
pub total_swap_fee: u64,
pub padding: [u8; 56],
/// When to begin scaling down the initial asset weight
crispheaney marked this conversation as resolved.
Show resolved Hide resolved
pub scale_initial_asset_weight_start: u64,
pub padding: [u8; 48],
}

impl Default for SpotMarket {
Expand Down Expand Up @@ -224,7 +226,8 @@ impl Default for SpotMarket {
flash_loan_amount: 0,
flash_loan_initial_token_amount: 0,
total_swap_fee: 0,
padding: [0; 56],
scale_initial_asset_weight_start: 0,
padding: [0; 48],
}
}
}
Expand Down Expand Up @@ -274,6 +277,7 @@ impl SpotMarket {
pub fn get_asset_weight(
&self,
size: u128,
oracle_price: i64,
margin_requirement_type: &MarginRequirementType,
) -> DriftResult<u32> {
let size_precision = 10_u128.pow(self.decimals);
Expand All @@ -286,7 +290,7 @@ impl SpotMarket {

let default_asset_weight = match margin_requirement_type {
MarginRequirementType::Initial | MarginRequirementType::Fill => {
self.initial_asset_weight
self.get_scaled_initial_asset_weight(oracle_price)?
}
MarginRequirementType::Maintenance => self.maintenance_asset_weight,
};
Expand All @@ -302,6 +306,30 @@ impl SpotMarket {
Ok(asset_weight)
}

pub fn get_scaled_initial_asset_weight(&self, oracle_price: i64) -> DriftResult<u32> {
if self.scale_initial_asset_weight_start == 0 {
return Ok(self.initial_asset_weight);
}

let deposits = self.get_deposits()?;
let deposit_value =
get_token_value(deposits.cast()?, self.decimals, oracle_price)?.cast::<u128>()?;
crispheaney marked this conversation as resolved.
Show resolved Hide resolved

let scale_initial_asset_weight_start =
self.scale_initial_asset_weight_start.cast::<u128>()?;
let asset_weight = if deposit_value < scale_initial_asset_weight_start {
self.initial_asset_weight
} else {
self.initial_asset_weight
.cast::<u128>()?
.safe_mul(scale_initial_asset_weight_start)?
.safe_div(deposit_value)?
.cast::<u32>()?
};

Ok(asset_weight)
}

pub fn get_liability_weight(
&self,
size: u128,
Expand Down
27 changes: 25 additions & 2 deletions sdk/src/math/spotBalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ export function getTokenValue(

export function calculateAssetWeight(
balanceAmount: BN,
oraclePrice: BN,
spotMarket: SpotMarketAccount,
marginCategory: MarginCategory
): BN {
Expand All @@ -174,7 +175,7 @@ export function calculateAssetWeight(
assetWeight = calculateSizeDiscountAssetWeight(
sizeInAmmReservePrecision,
new BN(spotMarket.imfFactor),
new BN(spotMarket.initialAssetWeight)
calculateScaledInitialAssetWeight(spotMarket, oraclePrice)
);
break;
case 'Maintenance':
Expand All @@ -185,13 +186,35 @@ export function calculateAssetWeight(
);
break;
default:
assetWeight = new BN(spotMarket.initialAssetWeight);
assetWeight = calculateScaledInitialAssetWeight(spotMarket, oraclePrice);
break;
}

return assetWeight;
}

export function calculateScaledInitialAssetWeight(
spotMarket: SpotMarketAccount,
oraclePrice: BN,
) : BN {
if (spotMarket.scaleInitialAssetWeightStart.eq(ZERO)) {
return new BN(spotMarket.initialAssetWeight);
}

const deposits = getTokenAmount(
spotMarket.depositBalance,
spotMarket,
SpotBalanceType.DEPOSIT
);
const depositsValue = getTokenValue(deposits, spotMarket.decimals, oraclePrice);

if (depositsValue.lt(spotMarket.scaleInitialAssetWeightStart)) {
return new BN(spotMarket.initialAssetWeight);
} else {
return new BN(spotMarket.initialAssetWeight).mul(spotMarket.scaleInitialAssetWeightStart).div(depositsValue);
}
}

export function calculateLiabilityWeight(
size: BN,
spotMarket: SpotMarketAccount,
Expand Down
3 changes: 2 additions & 1 deletion sdk/src/math/spotMarket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ export function castNumberToSpotPrecision(

export function calculateSpotMarketMarginRatio(
market: SpotMarketAccount,
oraclePrice: BN,
marginCategory: MarginCategory,
size: BN,
balanceType: SpotBalanceType
): number {
if (isVariant(balanceType, 'deposit')) {
const assetWeight = calculateAssetWeight(size, market, marginCategory);
const assetWeight = calculateAssetWeight(size, oraclePrice, market, marginCategory);
return MARGIN_PRECISION.sub(assetWeight).toNumber();
} else {
const liabilityWeight = calculateLiabilityWeight(
Expand Down
1 change: 1 addition & 0 deletions sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ export type SpotMarketAccount = {
maintenanceLiabilityWeight: number;
liquidatorFee: number;
imfFactor: number;
scaleInitialAssetWeightStart: BN;

withdrawGuardThreshold: BN;
depositTokenTwap: BN;
Expand Down
6 changes: 6 additions & 0 deletions sdk/src/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,7 @@ export class User {
if (marginCategory !== undefined) {
const weight = calculateAssetWeight(
tokenAmount,
oraclePriceData.price,
spotMarketAccount,
marginCategory
);
Expand Down Expand Up @@ -2052,6 +2053,7 @@ export class User {
if (signedTokenAmount.gt(ZERO)) {
const assetWeight = calculateAssetWeight(
signedTokenAmount,
this.driftClient.getOraclePriceDataAndSlot(market.oracle).data.price,
market,
'Maintenance'
);
Expand Down Expand Up @@ -2228,6 +2230,7 @@ export class User {
currentSpotMarketNetValue?: BN
): BN {
const market = this.driftClient.getSpotMarketAccount(targetMarketIndex);
const oraclePrice = this.driftClient.getOraclePriceDataAndSlot(market.oracle).data.price;

currentQuoteAssetValue = this.getSpotMarketAssetValue(
QUOTE_SPOT_MARKET_INDEX
Expand All @@ -2239,6 +2242,7 @@ export class User {
let freeCollateral = this.getFreeCollateral();
const marginRatio = calculateSpotMarketMarginRatio(
market,
oraclePrice,
'Initial',
ZERO,
isVariant(direction, 'long')
Expand All @@ -2253,6 +2257,7 @@ export class User {
tradeAmount = currentSpotMarketNetValue.abs();
const marginRatio = calculateSpotMarketMarginRatio(
market,
oraclePrice,
'Initial',
this.getTokenAmount(targetMarketIndex).abs(),
SpotBalanceType.BORROW
Expand All @@ -2267,6 +2272,7 @@ export class User {
tradeAmount = currentSpotMarketNetValue;
const marginRatio = calculateSpotMarketMarginRatio(
market,
oraclePrice,
'Initial',
this.getTokenAmount(targetMarketIndex),
SpotBalanceType.DEPOSIT
Expand Down
Loading