From e7af273a81b038867b98a530bddfae025cac6c44 Mon Sep 17 00:00:00 2001 From: lil perp Date: Thu, 26 Oct 2023 17:36:44 -0400 Subject: [PATCH] program: allow accelerated update user idle (#669) * program: allow accelerated update user idle * change to slots and add comment * CHANGELOG --- CHANGELOG.md | 1 + programs/drift/src/instructions/keeper.rs | 23 +++++++++++++++++++++-- programs/drift/src/validation/user.rs | 11 ++++++----- sdk/src/user.ts | 12 +++++++++++- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf33ffb0d..ea7d92bb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- program: add accelerated user update idle ([#669](https://github.com/drift-labs/protocol-v2/pull/669)) - program: make user status a bit flag ([#619](https://github.com/drift-labs/protocol-v2/pull/619)) - program: place and take uses auction end price for market orders ([#650](https://github.com/drift-labs/protocol-v2/pull/650)) - program: reduce cus for place_spot_order ([#662](https://github.com/drift-labs/protocol-v2/pull/662)) diff --git a/programs/drift/src/instructions/keeper.rs b/programs/drift/src/instructions/keeper.rs index 65636594c..ff6a7916f 100644 --- a/programs/drift/src/instructions/keeper.rs +++ b/programs/drift/src/instructions/keeper.rs @@ -8,6 +8,7 @@ use crate::instructions::optional_accounts::{ }; use crate::math::constants::QUOTE_SPOT_MARKET_INDEX; use crate::math::insurance::if_shares_to_vault_amount; +use crate::math::margin::calculate_user_equity; use crate::math::orders::{estimate_price_from_side, find_bids_and_asks_from_users}; use crate::math::spot_withdraw::validate_spot_market_vault_amount; use crate::state::fill_mode::FillMode; @@ -29,10 +30,10 @@ use crate::state::spot_market_map::{ use crate::state::state::State; use crate::state::user::{MarketType, OrderStatus, User, UserStats}; use crate::state::user_map::load_user_maps; -use crate::validate; use crate::validation::user::validate_user_is_idle; use crate::{controller, load, math}; use crate::{load_mut, QUOTE_PRECISION_U64}; +use crate::{validate, QUOTE_PRECISION_I128}; #[access_control( fill_not_paused(&ctx.accounts.state) @@ -357,7 +358,25 @@ pub fn handle_update_user_idle<'info>(ctx: Context) -> Result<() let mut user = load_mut!(ctx.accounts.user)?; let clock = Clock::get()?; - validate_user_is_idle(&user, clock.slot)?; + let AccountMaps { + perp_market_map, + spot_market_map, + mut oracle_map, + } = load_maps( + &mut ctx.remaining_accounts.iter().peekable(), + &MarketSet::new(), + &MarketSet::new(), + Clock::get()?.slot, + None, + )?; + + let (equity, _) = + calculate_user_equity(&user, &perp_market_map, &spot_market_map, &mut oracle_map)?; + + // user flipped to idle faster if equity is less than 1 + let accelerated = equity < QUOTE_PRECISION_I128; + + validate_user_is_idle(&user, clock.slot, accelerated)?; user.idle = true; diff --git a/programs/drift/src/validation/user.rs b/programs/drift/src/validation/user.rs index 670789ec0..0006fba53 100644 --- a/programs/drift/src/validation/user.rs +++ b/programs/drift/src/validation/user.rs @@ -52,13 +52,14 @@ pub fn validate_user_deletion(user: &User, user_stats: &UserStats) -> DriftResul Ok(()) } -pub fn validate_user_is_idle(user: &User, slot: u64) -> DriftResult { +pub fn validate_user_is_idle(user: &User, slot: u64, accelerated: bool) -> DriftResult { let slots_since_last_active = slot.saturating_sub(user.last_active_slot); - #[cfg(feature = "mainnet-beta")] - let slots_before_idle = 1512000_u64; - #[cfg(not(feature = "mainnet-beta"))] - let slots_before_idle = 0_u64; + let slots_before_idle = if accelerated { + 9000_u64 // 60 * 60 / .4 (~1 hour) + } else { + 1512000_u64 // 60 * 60 * 24 * 7 / .4 (~1 week) + }; validate!( slots_since_last_active >= slots_before_idle, diff --git a/sdk/src/user.ts b/sdk/src/user.ts index 02b836f67..defbc8abb 100644 --- a/sdk/src/user.ts +++ b/sdk/src/user.ts @@ -3148,12 +3148,22 @@ export class User { }; } - public canMakeIdle(slot: BN, slotsBeforeIdle: BN): boolean { + public canMakeIdle(slot: BN): boolean { const userAccount = this.getUserAccount(); if (userAccount.idle) { return false; } + const { totalAssetValue, totalLiabilityValue } = this.getSpotMarketAssetAndLiabilityValue(); + const equity = totalAssetValue.sub(totalLiabilityValue); + + let slotsBeforeIdle: BN; + if (equity.lt(QUOTE_PRECISION)) { + slotsBeforeIdle = new BN(9000); // 1 hour + } else { + slotsBeforeIdle = new BN(1512000); // 1 week + } + const userLastActiveSlot = userAccount.lastActiveSlot; const slotsSinceLastActive = slot.sub(userLastActiveSlot); if (slotsSinceLastActive.lt(slotsBeforeIdle)) {