From bcb2a0f1958451935077b1ef3f585c9f663e3d89 Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Mon, 16 Dec 2024 15:14:56 -0500 Subject: [PATCH] program: add ix to pause deposits/withdraws if vault invariant broken --- programs/drift/src/instructions/keeper.rs | 36 ++++++++++++++++++++++- programs/drift/src/lib.rs | 6 ++++ sdk/src/driftClient.ts | 32 ++++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/programs/drift/src/instructions/keeper.rs b/programs/drift/src/instructions/keeper.rs index c45c82d23..a0cf939b8 100644 --- a/programs/drift/src/instructions/keeper.rs +++ b/programs/drift/src/instructions/keeper.rs @@ -43,7 +43,7 @@ use crate::state::oracle_map::OracleMap; use crate::state::order_params::{ OrderParams, PlaceOrderOptions, SwiftOrderParamsMessage, SwiftServerMessage, }; -use crate::state::paused_operations::PerpOperation; +use crate::state::paused_operations::{PerpOperation, SpotOperation}; use crate::state::perp_market::{ContractType, MarketStatus, PerpMarket}; use crate::state::perp_market_map::{ get_market_set_for_spot_positions, get_market_set_for_user_positions, get_market_set_from_list, @@ -2409,6 +2409,27 @@ pub fn handle_force_delete_user<'c: 'info, 'info>( Ok(()) } +pub fn handle_pause_spot_market_deposit_withdraw( + ctx: Context, +) -> Result<()> { + let spot_market = &mut load_mut!(ctx.accounts.spot_market)?; + + let result =validate_spot_market_vault_amount(spot_market, ctx.accounts.spot_market_vault.amount); + + validate!( + matches!(result, Err(ErrorCode::SpotMarketVaultInvariantViolated)), + ErrorCode::DefaultError, + "spot market vault amount is valid" + )?; + + + spot_market.paused_operations = spot_market.paused_operations | SpotOperation::Deposit as u8; + spot_market.paused_operations = spot_market.paused_operations | SpotOperation::Withdraw as u8; + + Ok(()) +} + + #[derive(Accounts)] pub struct FillOrder<'info> { pub state: Box>, @@ -2905,3 +2926,16 @@ pub struct ForceDeleteUser<'info> { /// CHECK: forced drift_signer pub drift_signer: AccountInfo<'info>, } + +#[derive(Accounts)] +pub struct PauseSpotMarketDepositWithdraw<'info> { + pub state: Box>, + pub keeper: Signer<'info>, + #[account(mut)] + pub spot_market: AccountLoader<'info, SpotMarket>, + #[account( + seeds = [b"spot_market_vault".as_ref(), spot_market.load()?.market_index.to_le_bytes().as_ref()], + bump, + )] + pub spot_market_vault: Box>, +} diff --git a/programs/drift/src/lib.rs b/programs/drift/src/lib.rs index 444b11117..cd310a76b 100644 --- a/programs/drift/src/lib.rs +++ b/programs/drift/src/lib.rs @@ -728,6 +728,12 @@ pub mod drift { handle_post_multi_pyth_pull_oracle_updates_atomic(ctx, params) } + pub fn pause_spot_market_deposit_withdraw( + ctx: Context, + ) -> Result<()> { + handle_pause_spot_market_deposit_withdraw(ctx) + } + // Admin Instructions pub fn initialize(ctx: Context) -> Result<()> { diff --git a/sdk/src/driftClient.ts b/sdk/src/driftClient.ts index 63388bfb9..fc3fc5361 100644 --- a/sdk/src/driftClient.ts +++ b/sdk/src/driftClient.ts @@ -8936,6 +8936,38 @@ export class DriftClient { return ix; } + public async getPauseSpotMarketDepositWithdrawIx( + spotMarketIndex: number + ): Promise { + const spotMarket = await this.getSpotMarketAccount(spotMarketIndex); + return this.program.instruction.pauseSpotMarketDepositWithdraw( + spotMarketIndex, + { + accounts: { + state: await this.getStatePublicKey(), + keeper: this.wallet.publicKey, + spotMarket: spotMarket.pubkey, + spotMarketVault: spotMarket.vault, + }, + } + ); + } + + public async pauseSpotMarketDepositWithdraw( + spotMarketIndex: number, + txParams?: TxParams + ): Promise { + const { txSig } = await this.sendTransaction( + await this.buildTransaction( + await this.getPauseSpotMarketDepositWithdrawIx(spotMarketIndex), + txParams + ), + [], + this.opts + ); + return txSig; + } + private handleSignedTransaction(signedTxs: SignedTxData[]) { if (this.enableMetricsEvents && this.metricsEventEmitter) { this.metricsEventEmitter.emit('txSigned', signedTxs);