Skip to content

Commit b8a8030

Browse files
authored
Nour/parameterize dlp (#1731)
* add validates and test for withdraw limit * settlement max * update idl * merge conflicts
1 parent 19c88f8 commit b8a8030

File tree

11 files changed

+327
-12
lines changed

11 files changed

+327
-12
lines changed

programs/drift/src/instructions/admin.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4711,6 +4711,7 @@ pub fn handle_initialize_lp_pool(
47114711
max_mint_fee: i64,
47124712
revenue_rebalance_period: u64,
47134713
max_aum: u128,
4714+
max_settle_quote_amount_per_market: u64,
47144715
) -> Result<()> {
47154716
let mut lp_pool = ctx.accounts.lp_pool.load_init()?;
47164717
let mint = ctx.accounts.mint.key();
@@ -4724,11 +4725,11 @@ pub fn handle_initialize_lp_pool(
47244725
last_aum: 0,
47254726
last_aum_slot: 0,
47264727
last_aum_ts: 0,
4728+
max_settle_quote_amount: max_settle_quote_amount_per_market,
47274729
last_revenue_rebalance_ts: 0,
47284730
total_fees_received: 0,
47294731
total_fees_paid: 0,
47304732
total_mint_redeem_fees_paid: 0,
4731-
oldest_oracle_slot: 0,
47324733
bump: ctx.bumps.lp_pool,
47334734
min_mint_fee,
47344735
max_mint_fee_premium: max_mint_fee,
@@ -5016,6 +5017,7 @@ pub fn handle_initialize_constituent<'info>(
50165017
max_weight_deviation: i64,
50175018
swap_fee_min: i64,
50185019
swap_fee_max: i64,
5020+
max_borrow_token_amount: u64,
50195021
oracle_staleness_threshold: u64,
50205022
cost_to_trade_bps: i32,
50215023
constituent_derivative_index: Option<i16>,
@@ -5067,6 +5069,7 @@ pub fn handle_initialize_constituent<'info>(
50675069
constituent.mint = ctx.accounts.spot_market_mint.key();
50685070
constituent.token_vault = ctx.accounts.constituent_vault.key();
50695071
constituent.bump = ctx.bumps.constituent;
5072+
constituent.max_borrow_token_amount = max_borrow_token_amount;
50705073
constituent.lp_pool = lp_pool.pubkey;
50715074
constituent.constituent_index = (constituent_target_base.targets.len() - 1) as u16;
50725075
constituent.next_swap_id = 1;
@@ -5101,6 +5104,7 @@ pub struct ConstituentParams {
51015104
pub max_weight_deviation: Option<i64>,
51025105
pub swap_fee_min: Option<i64>,
51035106
pub swap_fee_max: Option<i64>,
5107+
pub max_borrow_token_amount: Option<u64>,
51045108
pub oracle_staleness_threshold: Option<u64>,
51055109
pub cost_to_trade_bps: Option<i32>,
51065110
pub constituent_derivative_index: Option<i16>,
@@ -5211,6 +5215,38 @@ pub fn handle_update_constituent_params<'info>(
52115215
constituent.xi = constituent_params.xi.unwrap();
52125216
}
52135217

5218+
if let Some(max_borrow_token_amount) = constituent_params.max_borrow_token_amount {
5219+
msg!(
5220+
"max_borrow_token_amount: {:?} -> {:?}",
5221+
constituent.max_borrow_token_amount,
5222+
max_borrow_token_amount
5223+
);
5224+
constituent.max_borrow_token_amount = max_borrow_token_amount;
5225+
}
5226+
5227+
Ok(())
5228+
}
5229+
5230+
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)]
5231+
pub struct LpPoolParams {
5232+
pub max_settle_quote_amount: Option<u64>,
5233+
}
5234+
5235+
pub fn handle_update_lp_pool_params<'info>(
5236+
ctx: Context<UpdateLpPoolParams>,
5237+
lp_pool_params: LpPoolParams,
5238+
) -> Result<()> {
5239+
let mut lp_pool = ctx.accounts.lp_pool.load_mut()?;
5240+
5241+
if let Some(max_settle_quote_amount) = lp_pool_params.max_settle_quote_amount {
5242+
msg!(
5243+
"max_settle_quote_amount: {:?} -> {:?}",
5244+
lp_pool.max_settle_quote_amount,
5245+
max_settle_quote_amount
5246+
);
5247+
lp_pool.max_settle_quote_amount = max_settle_quote_amount;
5248+
}
5249+
52145250
Ok(())
52155251
}
52165252

@@ -6683,6 +6719,18 @@ pub struct UpdateConstituentParams<'info> {
66836719
pub constituent: AccountLoader<'info, Constituent>,
66846720
}
66856721

6722+
#[derive(Accounts)]
6723+
pub struct UpdateLpPoolParams<'info> {
6724+
#[account(mut)]
6725+
pub lp_pool: AccountLoader<'info, LPPool>,
6726+
#[account(
6727+
mut,
6728+
constraint = admin.key() == admin_hot_wallet::id() || admin.key() == state.admin
6729+
)]
6730+
pub admin: Signer<'info>,
6731+
pub state: Box<Account<'info, State>>,
6732+
}
6733+
66866734
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Default)]
66876735
pub struct AddAmmConstituentMappingDatum {
66886736
pub constituent_index: u16,

programs/drift/src/instructions/keeper.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3046,7 +3046,14 @@ pub fn handle_settle_perp_to_lp_pool<'c: 'info, 'info>(
30463046
};
30473047

30483048
// Calculate settlement
3049-
let settlement_result = calculate_settlement_amount(&settlement_ctx)?;
3049+
let mut settlement_result = calculate_settlement_amount(&settlement_ctx)?;
3050+
3051+
// If transfering from perp market, dont do more than the max allowed
3052+
if settlement_result.direction == SettlementDirection::ToLpPool {
3053+
settlement_result.amount_transferred = settlement_result
3054+
.amount_transferred
3055+
.min(lp_pool.max_settle_quote_amount);
3056+
}
30503057

30513058
if settlement_result.direction == SettlementDirection::None {
30523059
continue;

programs/drift/src/instructions/lp_pool.rs

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::{
1616
constants::{PERCENTAGE_PRECISION_I64, PRICE_PRECISION},
1717
oracle::{is_oracle_valid_for_action, oracle_validity, DriftAction},
1818
safe_math::SafeMath,
19+
spot_balance,
1920
},
2021
math_error, msg, safe_decrement, safe_increment,
2122
state::{
@@ -246,7 +247,7 @@ pub fn handle_update_lp_pool_aum<'c: 'info, 'info>(
246247
ErrorCode::InvalidPDA,
247248
"Amm cache PDA does not match expected PDA"
248249
)?;
249-
250+
250251
let (aum, crypto_delta, derivative_groups) = lp_pool.update_aum(
251252
now,
252253
slot,
@@ -958,6 +959,9 @@ pub fn handle_deposit_to_program_vault<'c: 'info, 'info>(
958959
Some(ctx.accounts.state.oracle_guard_rails),
959960
)?;
960961

962+
constituent.sync_token_balance(ctx.accounts.constituent_token_account.amount);
963+
let balance_before = constituent.get_full_balance(&spot_market)?;
964+
961965
if amount == 0 {
962966
return Err(ErrorCode::InsufficientDeposit.into());
963967
}
@@ -1000,6 +1004,8 @@ pub fn handle_deposit_to_program_vault<'c: 'info, 'info>(
10001004
safe_increment!(spot_position.cumulative_deposits, amount.cast()?);
10011005

10021006
ctx.accounts.spot_market_vault.reload()?;
1007+
ctx.accounts.constituent_token_account.reload()?;
1008+
constituent.sync_token_balance(ctx.accounts.constituent_token_account.amount);
10031009
spot_market.validate_max_token_deposits_and_borrows(false)?;
10041010

10051011
validate!(
@@ -1008,6 +1014,15 @@ pub fn handle_deposit_to_program_vault<'c: 'info, 'info>(
10081014
"Spot market vault amount mismatch after deposit"
10091015
)?;
10101016

1017+
validate!(
1018+
constituent
1019+
.get_full_balance(&spot_market)?
1020+
.abs_diff(balance_before)
1021+
<= 1,
1022+
ErrorCode::LpInvariantFailed,
1023+
"Constituent balance mismatch after desposit to program vault"
1024+
)?;
1025+
10111026
Ok(())
10121027
}
10131028

@@ -1028,6 +1043,10 @@ pub fn handle_withdraw_from_program_vault<'c: 'info, 'info>(
10281043
Some(ctx.accounts.state.oracle_guard_rails),
10291044
)?;
10301045

1046+
constituent.sync_token_balance(ctx.accounts.constituent_token_account.amount);
1047+
1048+
let balance_before = constituent.get_full_balance(&spot_market)?;
1049+
10311050
if amount == 0 {
10321051
return Err(ErrorCode::InsufficientDeposit.into());
10331052
}
@@ -1045,35 +1064,65 @@ pub fn handle_withdraw_from_program_vault<'c: 'info, 'info>(
10451064
clock.unix_timestamp,
10461065
)?;
10471066

1067+
// Can only borrow up to the max
1068+
let token_amount = constituent.spot_balance.get_token_amount(&spot_market)?;
1069+
let amount_to_transfer = if constituent.spot_balance.balance_type == SpotBalanceType::Borrow {
1070+
amount.min(
1071+
constituent
1072+
.max_borrow_token_amount
1073+
.safe_sub(token_amount as u64)?,
1074+
)
1075+
} else {
1076+
amount.min(
1077+
constituent
1078+
.max_borrow_token_amount
1079+
.safe_add(token_amount as u64)?,
1080+
)
1081+
};
1082+
10481083
controller::token::send_from_program_vault(
10491084
&ctx.accounts.token_program,
10501085
&spot_market_vault,
10511086
&ctx.accounts.constituent_token_account,
10521087
&ctx.accounts.drift_signer,
10531088
state.signer_nonce,
1054-
amount,
1089+
amount_to_transfer,
10551090
&Some(*ctx.accounts.mint.clone()),
10561091
)?;
1092+
ctx.accounts.constituent_token_account.reload()?;
1093+
constituent.sync_token_balance(ctx.accounts.constituent_token_account.amount);
10571094

10581095
// Adjust BLPosition for the new deposits
10591096
let spot_position = &mut constituent.spot_balance;
10601097
update_spot_balances(
1061-
amount as u128,
1098+
amount_to_transfer as u128,
10621099
&SpotBalanceType::Borrow,
10631100
&mut spot_market,
10641101
spot_position,
10651102
true,
10661103
)?;
10671104

1068-
safe_decrement!(spot_position.cumulative_deposits, amount.cast()?);
1105+
safe_decrement!(
1106+
spot_position.cumulative_deposits,
1107+
amount_to_transfer.cast()?
1108+
);
10691109

10701110
ctx.accounts.spot_market_vault.reload()?;
1111+
spot_market.validate_max_token_deposits_and_borrows(true)?;
1112+
10711113
math::spot_withdraw::validate_spot_market_vault_amount(
10721114
&spot_market,
10731115
ctx.accounts.spot_market_vault.amount,
10741116
)?;
10751117

1076-
spot_market.validate_max_token_deposits_and_borrows(true)?;
1118+
validate!(
1119+
constituent
1120+
.get_full_balance(&spot_market)?
1121+
.abs_diff(balance_before)
1122+
<= 1,
1123+
ErrorCode::LpInvariantFailed,
1124+
"Constituent balance mismatch after withdraw from program vault"
1125+
)?;
10771126

10781127
Ok(())
10791128
}

programs/drift/src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,6 +1759,7 @@ pub mod drift {
17591759
max_mint_fee: i64,
17601760
revenue_rebalance_period: u64,
17611761
max_aum: u128,
1762+
max_settle_quote_amount_per_market: u64,
17621763
) -> Result<()> {
17631764
handle_initialize_lp_pool(
17641765
ctx,
@@ -1767,6 +1768,7 @@ pub mod drift {
17671768
max_mint_fee,
17681769
revenue_rebalance_period,
17691770
max_aum,
1771+
max_settle_quote_amount_per_market,
17701772
)
17711773
}
17721774

@@ -1824,6 +1826,7 @@ pub mod drift {
18241826
max_weight_deviation: i64,
18251827
swap_fee_min: i64,
18261828
swap_fee_max: i64,
1829+
max_borrow_token_amount: u64,
18271830
oracle_staleness_threshold: u64,
18281831
cost_to_trade: i32,
18291832
constituent_derivative_index: Option<i16>,
@@ -1842,6 +1845,7 @@ pub mod drift {
18421845
max_weight_deviation,
18431846
swap_fee_min,
18441847
swap_fee_max,
1848+
max_borrow_token_amount,
18451849
oracle_staleness_threshold,
18461850
cost_to_trade,
18471851
constituent_derivative_index,
@@ -1862,6 +1866,13 @@ pub mod drift {
18621866
handle_update_constituent_params(ctx, constituent_params)
18631867
}
18641868

1869+
pub fn update_lp_pool_params(
1870+
ctx: Context<UpdateLpPoolParams>,
1871+
lp_pool_params: LpPoolParams,
1872+
) -> Result<()> {
1873+
handle_update_lp_pool_params(ctx, lp_pool_params)
1874+
}
1875+
18651876
pub fn add_amm_constituent_mapping_data(
18661877
ctx: Context<AddAmmConstituentMappingData>,
18671878
amm_constituent_mapping_data: Vec<AddAmmConstituentMappingDatum>,

programs/drift/src/state/constituent_map.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ impl<'a> ConstituentMap<'a> {
133133
)?;
134134

135135
// constituent index 276 bytes from front of account
136-
let constituent_index = u16::from_le_bytes(*array_ref![data, 284, 2]);
136+
let constituent_index = u16::from_le_bytes(*array_ref![data, 292, 2]);
137137
if constituent_map.0.contains_key(&constituent_index) {
138138
msg!(
139139
"Can not include same constituent index twice {}",

programs/drift/src/state/lp_pool.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ pub struct LPPool {
7676
pub last_aum_ts: i64, // 8, 160
7777

7878
/// Oldest slot of constituent oracles
79-
pub oldest_oracle_slot: u64,
79+
pub max_settle_quote_amount: u64,
8080

8181
/// timestamp of last vAMM revenue rebalance
8282
pub last_revenue_rebalance_ts: u64, // 8, 168
@@ -731,7 +731,6 @@ impl LPPool {
731731
}
732732
aum = aum_i128.max(0i128).cast::<u128>()?;
733733

734-
self.oldest_oracle_slot = oldest_slot;
735734
self.last_aum = aum;
736735
self.last_aum_slot = slot;
737736
self.last_aum_ts = now;
@@ -819,6 +818,10 @@ pub struct Constituent {
819818
/// precision: PERCENTAGE_PRECISION
820819
pub swap_fee_max: i64,
821820

821+
/// Max Borrow amount:
822+
/// precision: token precision
823+
pub max_borrow_token_amount: u64,
824+
822825
/// ata token balance in token precision
823826
pub token_balance: u64,
824827

@@ -859,7 +862,7 @@ pub struct Constituent {
859862
}
860863

861864
impl Size for Constituent {
862-
const SIZE: usize = 296;
865+
const SIZE: usize = 304;
863866
}
864867

865868
impl Constituent {

0 commit comments

Comments
 (0)