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: add-spot-borrow-insurance-limits #1080

Merged
merged 11 commits into from
Jun 20, 2024
53 changes: 50 additions & 3 deletions programs/drift/src/instructions/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub fn handle_initialize_spot_market(
return Err(ErrorCode::InvalidInsuranceFundAuthority.into());
}

validate_borrow_rate(optimal_utilization, optimal_borrow_rate, max_borrow_rate)?;
validate_borrow_rate(optimal_utilization, optimal_borrow_rate, max_borrow_rate, 0)?;

let spot_market_index = get_then_update_id!(state, number_of_spot_markets);

Expand Down Expand Up @@ -278,7 +278,9 @@ pub fn handle_initialize_spot_market(
flash_loan_initial_token_amount: 0,
total_swap_fee: 0,
scale_initial_asset_weight_start,
padding: [0; 48],
max_token_borrows: 0,
min_borrow_rate: 0,
padding: [0; 36],
insurance_fund: InsuranceFund {
vault: *ctx.accounts.insurance_fund_vault.to_account_info().key,
unstaking_period: THIRTEEN_DAY,
Expand Down Expand Up @@ -2246,9 +2248,15 @@ pub fn handle_update_spot_market_borrow_rate(
optimal_utilization: u32,
optimal_borrow_rate: u32,
max_borrow_rate: u32,
min_borrow_rate: Option<u32>,
) -> Result<()> {
let spot_market = &mut load_mut!(ctx.accounts.spot_market)?;
validate_borrow_rate(optimal_utilization, optimal_borrow_rate, max_borrow_rate)?;
validate_borrow_rate(
optimal_utilization,
optimal_borrow_rate,
max_borrow_rate,
min_borrow_rate.unwrap_or(spot_market.min_borrow_rate),
)?;

msg!(
"spot_market.optimal_utilization: {:?} -> {:?}",
Expand All @@ -2271,6 +2279,16 @@ pub fn handle_update_spot_market_borrow_rate(
spot_market.optimal_utilization = optimal_utilization;
spot_market.optimal_borrow_rate = optimal_borrow_rate;
spot_market.max_borrow_rate = max_borrow_rate;

if let Some(min_borrow_rate) = min_borrow_rate {
msg!(
"spot_market.min_borrow_rate: {:?} -> {:?}",
spot_market.min_borrow_rate,
min_borrow_rate
);
spot_market.min_borrow_rate = min_borrow_rate
}

Ok(())
}

Expand All @@ -2293,6 +2311,35 @@ pub fn handle_update_spot_market_max_token_deposits(
Ok(())
}

#[access_control(
spot_market_valid(&ctx.accounts.spot_market)
)]
pub fn handle_update_spot_market_max_token_borrows(
ctx: Context<AdminUpdateSpotMarket>,
max_token_borrows: u64,
) -> Result<()> {
let spot_market = &mut load_mut!(ctx.accounts.spot_market)?;

msg!(
"spot_market.max_token_borrows: {:?} -> {:?}",
spot_market.max_token_borrows,
max_token_borrows
);

let current_spot_tokens_borrows: u64 = spot_market.get_borrows()?.cast()?;

validate!(
current_spot_tokens_borrows <= max_token_borrows,
ErrorCode::InvalidSpotMarketInitialization,
"spot borrows {} > max_token_borrows {}",
current_spot_tokens_borrows,
max_token_borrows
)?;

spot_market.max_token_borrows = max_token_borrows;
Ok(())
}

#[access_control(
spot_market_valid(&ctx.accounts.spot_market)
)]
Expand Down
2 changes: 2 additions & 0 deletions programs/drift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -919,12 +919,14 @@ pub mod drift {
optimal_utilization: u32,
optimal_borrow_rate: u32,
max_borrow_rate: u32,
min_borrow_rate: Option<u32>,
) -> Result<()> {
handle_update_spot_market_borrow_rate(
ctx,
optimal_utilization,
optimal_borrow_rate,
max_borrow_rate,
min_borrow_rate,
)
}

Expand Down
3 changes: 2 additions & 1 deletion programs/drift/src/math/spot_balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ pub fn calculate_accumulated_interest(
utilization
.safe_mul(borrow_rate_slope)?
.safe_div(SPOT_UTILIZATION_PRECISION)?
};
}
.max(spot_market.min_borrow_rate.cast()?);

let time_since_last_update = now
.cast::<u64>()
Expand Down
26 changes: 24 additions & 2 deletions programs/drift/src/state/spot_market.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,14 @@ pub struct SpotMarket {
/// disabled when 0
/// precision: QUOTE_PRECISION
pub scale_initial_asset_weight_start: u64,
pub padding: [u8; 48],
/// When to begin scaling down the initial asset weight
/// disabled when 0
/// precision: QUOTE_PRECISION
pub max_token_borrows: u64,
/// The min borrow rate for this market when the market regardless of utilization
/// precision: SPOT_RATE_PRECISION
pub min_borrow_rate: u32,
pub padding: [u8; 36],
}

impl Default for SpotMarket {
Expand Down Expand Up @@ -239,7 +246,9 @@ impl Default for SpotMarket {
flash_loan_initial_token_amount: 0,
total_swap_fee: 0,
scale_initial_asset_weight_start: 0,
padding: [0; 48],
max_token_borrows: 0,
min_borrow_rate: 0,
padding: [0; 36],
}
}
}
Expand Down Expand Up @@ -426,6 +435,19 @@ impl SpotMarket {
deposits,
)?;

if self.max_token_borrows > 0 {
0xbigz marked this conversation as resolved.
Show resolved Hide resolved
let borrows = self.get_borrows()?;
let max_token_borrows = self.max_token_borrows.cast::<u128>()?;

validate!(
max_token_borrows == 0 || borrows <= max_token_borrows,
ErrorCode::MaxDeposit,
"max token amount ({}) < borrows ({})",
max_token_borrows,
borrows,
)?;
}

Ok(())
}

Expand Down
11 changes: 10 additions & 1 deletion programs/drift/src/validation/spot_market.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub fn validate_borrow_rate(
optimal_utilization: u32,
optimal_borrow_rate: u32,
max_borrow_rate: u32,
min_borrow_rate: u32,
) -> DriftResult {
validate!(
optimal_utilization <= SPOT_UTILIZATION_PRECISION_U32,
Expand All @@ -18,10 +19,18 @@ pub fn validate_borrow_rate(
validate!(
optimal_borrow_rate <= max_borrow_rate,
ErrorCode::InvalidSpotMarketInitialization,
"For spot market, optimal borrow rate ({}) must be < max borrow rate ({})",
"For spot market, optimal borrow rate ({}) must be <= max borrow rate ({})",
optimal_borrow_rate,
max_borrow_rate
)?;

validate!(
optimal_borrow_rate >= min_borrow_rate,
ErrorCode::InvalidSpotMarketInitialization,
"For spot market, optimal borrow rate ({}) must be >= min borrow rate ({})",
optimal_borrow_rate,
min_borrow_rate
)?;

Ok(())
}
48 changes: 45 additions & 3 deletions sdk/src/adminClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1812,6 +1812,44 @@ export class AdminClient extends DriftClient {
);
}

public async updateSpotMarketMaxTokenBorrows(
spotMarketIndex: number,
maxTokenBorrows: BN
): Promise<TransactionSignature> {
const updateSpotMarketMaxTokenBorrowsIx =
await this.getUpdateSpotMarketMaxTokenBorrowsIx(
spotMarketIndex,
maxTokenBorrows
);

const tx = await this.buildTransaction(updateSpotMarketMaxTokenBorrowsIx);

const { txSig } = await this.sendTransaction(tx, [], this.opts);

return txSig;
}

public async getUpdateSpotMarketMaxTokenBorrowsIx(
spotMarketIndex: number,
maxTokenBorrows: BN
): Promise<TransactionInstruction> {
return this.program.instruction.updateSpotMarketMaxTokenBorrows(
maxTokenBorrows,
{
accounts: {
admin: this.isSubscribed
? this.getStateAccount().admin
: this.wallet.publicKey,
state: await this.getStatePublicKey(),
spotMarket: await getSpotMarketPublicKey(
this.program.programId,
spotMarketIndex
),
},
}
);
}

public async updateSpotMarketScaleInitialAssetWeightStart(
spotMarketIndex: number,
scaleInitialAssetWeightStart: BN
Expand Down Expand Up @@ -2506,14 +2544,16 @@ export class AdminClient extends DriftClient {
spotMarketIndex: number,
optimalUtilization: number,
optimalBorrowRate: number,
optimalMaxRate: number
optimalMaxRate: number,
minBorrowRate?: number | undefined
): Promise<TransactionSignature> {
const updateSpotMarketBorrowRateIx =
await this.getUpdateSpotMarketBorrowRateIx(
spotMarketIndex,
optimalUtilization,
optimalBorrowRate,
optimalMaxRate
optimalMaxRate,
minBorrowRate
);

const tx = await this.buildTransaction(updateSpotMarketBorrowRateIx);
Expand All @@ -2527,12 +2567,14 @@ export class AdminClient extends DriftClient {
spotMarketIndex: number,
optimalUtilization: number,
optimalBorrowRate: number,
optimalMaxRate: number
optimalMaxRate: number,
minBorrowRate?: number | undefined
): Promise<TransactionInstruction> {
return await this.program.instruction.updateSpotMarketBorrowRate(
optimalUtilization,
optimalBorrowRate,
optimalMaxRate,
minBorrowRate,
{
accounts: {
admin: this.isSubscribed
Expand Down
9 changes: 8 additions & 1 deletion sdk/src/math/spotBalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,13 @@ export function calculateSpotMarketBorrowCapacity(
remainingCapacity = BN.max(ZERO, totalCapacity.sub(tokenBorrowAmount));
}

if (spotMarketAccount.maxTokenBorrows.gt(ZERO)) {
0xbigz marked this conversation as resolved.
Show resolved Hide resolved
remainingCapacity = BN.min(
remainingCapacity,
BN.max(ZERO, spotMarketAccount.maxTokenBorrows.sub(tokenBorrowAmount))
);
}

return { totalCapacity, remainingCapacity };
}

Expand Down Expand Up @@ -395,7 +402,7 @@ export function calculateInterestRate(
.div(SPOT_MARKET_UTILIZATION_PRECISION);
}

return interestRate;
return BN.max(interestRate, new BN(bank.minBorrowRate));
}

export function calculateDepositRate(
Expand Down
3 changes: 3 additions & 0 deletions sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,9 @@ export type SpotMarketAccount = {
pausedOperations: number;

ifPausedOperations: number;

maxTokenBorrows: BN;
minBorrowRate: number;
};

export type PoolBalance = {
Expand Down
Loading