diff --git a/programs/drift/src/controller/amm.rs b/programs/drift/src/controller/amm.rs index 7162e9d2d..e44724cb5 100644 --- a/programs/drift/src/controller/amm.rs +++ b/programs/drift/src/controller/amm.rs @@ -493,14 +493,14 @@ fn calculate_revenue_pool_transfer( market: &PerpMarket, spot_market: &SpotMarket, amm_fee_pool_token_amount_after: u128, - terminal_state_surplus: i128, + market_surplus: i128, ) -> DriftResult { // Calculates the revenue pool transfer amount for a given market state (positive = send to revenue pool, negative = pull from revenue pool) // If the AMM budget is above `FEE_POOL_TO_REVENUE_POOL_THRESHOLD` (in surplus), settle fees collected to the revenue pool depending on the health of the AMM state - // Otherwise, spull from the revenue pool (up to a constraint amount) + // Otherwise, pull from the revenue pool (up to a constraint amount) let amm_budget_surplus = - terminal_state_surplus.saturating_sub(FEE_POOL_TO_REVENUE_POOL_THRESHOLD.cast()?); + market_surplus.saturating_sub(FEE_POOL_TO_REVENUE_POOL_THRESHOLD.cast()?); if amm_budget_surplus > 0 { let fee_pool_threshold = amm_fee_pool_token_amount_after @@ -553,20 +553,22 @@ fn calculate_revenue_pool_transfer( Ok(revenue_pool_transfer) } else if amm_budget_surplus < 0 { + // auto withdraw only from pool only when revenue pool has some buffer + + let revenue_pool_balance: u128 = get_token_amount( + spot_market.revenue_pool.scaled_balance, + spot_market, + &SpotBalanceType::Deposit, + )? + .cast()?; + let max_revenue_withdraw_allowed = market .insurance_claim .max_revenue_withdraw_per_period .cast::()? .saturating_sub(market.insurance_claim.revenue_withdraw_since_last_settle) .cast::()? - .min( - get_token_amount( - spot_market.revenue_pool.scaled_balance, - spot_market, - &SpotBalanceType::Deposit, - )? - .cast()?, - ) + .min(revenue_pool_balance.saturating_sub(FEE_POOL_TO_REVENUE_POOL_THRESHOLD)) .min( market .insurance_claim @@ -665,10 +667,7 @@ pub fn update_pool_balances( market.amm.fee_pool.balance_type(), )?; - let terminal_state_surplus = market - .amm - .total_fee_minus_distributions - .safe_sub(market.amm.total_fee_withdrawn.cast()?)?; + let market_surplus = market.amm.total_fee_minus_distributions; // market can perform withdraw from revenue pool if spot_market.insurance_fund.last_revenue_settle_ts @@ -688,7 +687,7 @@ pub fn update_pool_balances( market, spot_market, amm_fee_pool_token_amount_after, - terminal_state_surplus, + market_surplus, )?; match revenue_pool_transfer.cmp(&0) { @@ -710,6 +709,10 @@ pub fn update_pool_balances( spot_market, &mut market.amm.fee_pool, )?; + market.amm.total_fee_withdrawn = market + .amm + .total_fee_withdrawn + .saturating_sub(revenue_pool_transfer.unsigned_abs()); } Ordering::Equal => (), } diff --git a/programs/drift/src/instructions/keeper.rs b/programs/drift/src/instructions/keeper.rs index 0fc1fc385..abe2bc8e5 100644 --- a/programs/drift/src/instructions/keeper.rs +++ b/programs/drift/src/instructions/keeper.rs @@ -2579,8 +2579,17 @@ pub fn handle_update_prelaunch_oracle(ctx: Context) -> Re )] pub fn handle_update_perp_bid_ask_twap<'c: 'info, 'info>( ctx: Context<'_, '_, 'c, 'info, UpdatePerpBidAskTwap<'info>>, + update_market_summary_stats: bool, ) -> Result<()> { let perp_market = &mut load_mut!(ctx.accounts.perp_market)?; + let spot_market = &mut load_mut!(ctx.accounts.quote_spot_market)?; + + validate!( + spot_market.market_index == QUOTE_SPOT_MARKET_INDEX, + ErrorCode::DefaultError, + "invalid spot market" + )?; + let clock = Clock::get()?; let now = clock.unix_timestamp; let slot = clock.slot; @@ -2677,6 +2686,16 @@ pub fn handle_update_perp_bid_ask_twap<'c: 'info, 'info>( )?; } + if update_market_summary_stats { + let new_total_fees_minus_distributions = calculate_perp_market_amm_summary_stats( + perp_market, + spot_market, + mm_oracle_price_data.get_price(), + false, + ); + perp_market.amm.total_fee_minus_distributions = new_total_fees_minus_distributions; + } + let funding_paused = state.funding_paused()? || perp_market.is_operation_paused(PerpOperation::UpdateFunding); controller::funding::update_funding_rate( @@ -3748,6 +3767,7 @@ pub struct UpdatePerpBidAskTwap<'info> { pub state: Box>, #[account(mut)] pub perp_market: AccountLoader<'info, PerpMarket>, + pub quote_spot_market: AccountLoader<'info, SpotMarket>, /// CHECK: checked in `update_funding_rate` ix constraint pub oracle: AccountInfo<'info>, pub keeper_stats: AccountLoader<'info, UserStats>, diff --git a/programs/drift/src/lib.rs b/programs/drift/src/lib.rs index a393cf067..f41248b25 100644 --- a/programs/drift/src/lib.rs +++ b/programs/drift/src/lib.rs @@ -701,8 +701,9 @@ pub mod drift { pub fn update_perp_bid_ask_twap<'c: 'info, 'info>( ctx: Context<'_, '_, 'c, 'info, UpdatePerpBidAskTwap<'info>>, + update_market_summary_stats: bool, ) -> Result<()> { - handle_update_perp_bid_ask_twap(ctx) + handle_update_perp_bid_ask_twap(ctx, update_market_summary_stats) } pub fn update_spot_market_cumulative_interest( diff --git a/programs/drift/src/math/constants.rs b/programs/drift/src/math/constants.rs index dc6ffeb94..965bbb8f8 100644 --- a/programs/drift/src/math/constants.rs +++ b/programs/drift/src/math/constants.rs @@ -147,7 +147,7 @@ pub const INSURANCE_C_MAX: u64 = ONE_HUNDRED_THOUSAND_QUOTE; pub const INSURANCE_SPECULATIVE_MAX: u64 = 0; // QUOTE THRESHOLDS -pub const FEE_POOL_TO_REVENUE_POOL_THRESHOLD: u128 = TWO_HUNDRED_FIFTY_QUOTE as u128; +pub const FEE_POOL_TO_REVENUE_POOL_THRESHOLD: u128 = ONE_THOUSAND_QUOTE as u128; // FEES pub const ONE_BPS_DENOMINATOR: u32 = 10000; diff --git a/sdk/src/driftClient.ts b/sdk/src/driftClient.ts index 2d1ecb13a..62118fb79 100644 --- a/sdk/src/driftClient.ts +++ b/sdk/src/driftClient.ts @@ -9269,9 +9269,11 @@ export class DriftClient { public async getUpdatePerpBidAskTwapIx( perpMarketIndex: number, - makers: [PublicKey, PublicKey][] + makers: [PublicKey, PublicKey][], + updateMarketSummaryStats = true ): Promise { const perpMarket = this.getPerpMarketAccount(perpMarketIndex); + const spotMarket = this.getQuoteSpotMarketAccount(); const remainingAccounts = []; for (const [maker, makerStats] of makers) { @@ -9287,16 +9289,20 @@ export class DriftClient { }); } - return await this.program.instruction.updatePerpBidAskTwap({ - accounts: { - state: await this.getStatePublicKey(), - perpMarket: perpMarket.pubkey, - oracle: perpMarket.amm.oracle, - authority: this.wallet.publicKey, - keeperStats: this.getUserStatsAccountPublicKey(), - }, - remainingAccounts, - }); + return await this.program.instruction.updatePerpBidAskTwap( + updateMarketSummaryStats, + { + accounts: { + state: await this.getStatePublicKey(), + perpMarket: perpMarket.pubkey, + quoteSpotMarket: spotMarket.pubkey, + oracle: perpMarket.amm.oracle, + authority: this.wallet.publicKey, + keeperStats: this.getUserStatsAccountPublicKey(), + }, + remainingAccounts, + } + ); } public async settleFundingPayment(