mango account freeze (#372)
* mango account freeze Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * format Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fixes from review Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * Fixes from review Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
parent
5ef04d6d08
commit
7c69197505
|
@ -81,6 +81,8 @@ pub enum MangoError {
|
||||||
HasLiquidatablePerpBasePosition,
|
HasLiquidatablePerpBasePosition,
|
||||||
#[msg("has liquidatable trusted perp pnl")]
|
#[msg("has liquidatable trusted perp pnl")]
|
||||||
HasLiquidatableTrustedPerpPnl,
|
HasLiquidatableTrustedPerpPnl,
|
||||||
|
#[msg("account is frozen")]
|
||||||
|
AccountIsFrozen,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MangoError {
|
impl MangoError {
|
||||||
|
|
|
@ -15,6 +15,7 @@ pub struct AccountClose<'info> {
|
||||||
mut,
|
mut,
|
||||||
has_one = group,
|
has_one = group,
|
||||||
has_one = owner,
|
has_one = owner,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen,
|
||||||
close = sol_destination
|
close = sol_destination
|
||||||
)]
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
|
@ -14,7 +14,8 @@ pub struct AccountEdit<'info> {
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group,
|
has_one = group,
|
||||||
has_one = owner
|
has_one = owner,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
)]
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
pub owner: Signer<'info>,
|
pub owner: Signer<'info>,
|
||||||
|
|
|
@ -14,7 +14,8 @@ pub struct AccountExpand<'info> {
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group,
|
has_one = group,
|
||||||
has_one = owner
|
has_one = owner,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
)]
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
pub owner: Signer<'info>,
|
pub owner: Signer<'info>,
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
use anchor_lang::prelude::*;
|
||||||
|
|
||||||
|
use crate::error::MangoError;
|
||||||
|
use crate::state::*;
|
||||||
|
|
||||||
|
#[derive(Accounts)]
|
||||||
|
pub struct AccountToggleFreeze<'info> {
|
||||||
|
#[account(
|
||||||
|
constraint = group.load()?.is_operational() @ MangoError::GroupIsHalted,
|
||||||
|
constraint = group.load()?.admin == admin.key() || group.load()?.security_admin == admin.key(),
|
||||||
|
)]
|
||||||
|
pub group: AccountLoader<'info, Group>,
|
||||||
|
|
||||||
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
)]
|
||||||
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
||||||
|
pub admin: Signer<'info>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Freezing an account, prevents all instructions involving account (also settling and liquidation), except
|
||||||
|
// perp consume events and force cancellation of orders
|
||||||
|
pub fn account_toggle_freeze(ctx: Context<AccountToggleFreeze>, freeze: bool) -> Result<()> {
|
||||||
|
let mut account = ctx.accounts.account.load_full_mut()?;
|
||||||
|
if freeze {
|
||||||
|
let now_ts: u64 = Clock::get()?.unix_timestamp.try_into().unwrap();
|
||||||
|
account.fixed.frozen_until = now_ts + 7 * 24 * 60 * 60;
|
||||||
|
} else {
|
||||||
|
account.fixed.frozen_until = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -31,6 +31,9 @@ pub mod jupiter_mainnet_3 {
|
||||||
/// 4. the mango group
|
/// 4. the mango group
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
pub struct FlashLoanBegin<'info> {
|
pub struct FlashLoanBegin<'info> {
|
||||||
|
#[account(
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
// owner is checked at #1
|
// owner is checked at #1
|
||||||
pub owner: Signer<'info>,
|
pub owner: Signer<'info>,
|
||||||
|
@ -53,7 +56,10 @@ pub struct FlashLoanBegin<'info> {
|
||||||
/// 4. the mango group
|
/// 4. the mango group
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
pub struct FlashLoanEnd<'info> {
|
pub struct FlashLoanEnd<'info> {
|
||||||
#[account(mut)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
// owner is checked at #1
|
// owner is checked at #1
|
||||||
pub owner: Signer<'info>,
|
pub owner: Signer<'info>,
|
||||||
|
|
|
@ -18,7 +18,10 @@ pub struct HealthRegionBegin<'info> {
|
||||||
#[account(address = tx_instructions::ID)]
|
#[account(address = tx_instructions::ID)]
|
||||||
pub instructions: UncheckedAccount<'info>,
|
pub instructions: UncheckedAccount<'info>,
|
||||||
|
|
||||||
#[account(mut)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +30,10 @@ pub struct HealthRegionBegin<'info> {
|
||||||
/// remaining_accounts: health accounts for account
|
/// remaining_accounts: health accounts for account
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
pub struct HealthRegionEnd<'info> {
|
pub struct HealthRegionEnd<'info> {
|
||||||
#[account(mut)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ pub use account_close::*;
|
||||||
pub use account_create::*;
|
pub use account_create::*;
|
||||||
pub use account_edit::*;
|
pub use account_edit::*;
|
||||||
pub use account_expand::*;
|
pub use account_expand::*;
|
||||||
|
pub use account_toggle_freeze::*;
|
||||||
pub use alt_extend::*;
|
pub use alt_extend::*;
|
||||||
pub use alt_set::*;
|
pub use alt_set::*;
|
||||||
pub use benchmark::*;
|
pub use benchmark::*;
|
||||||
|
@ -56,6 +57,7 @@ mod account_close;
|
||||||
mod account_create;
|
mod account_create;
|
||||||
mod account_edit;
|
mod account_edit;
|
||||||
mod account_expand;
|
mod account_expand;
|
||||||
|
mod account_toggle_freeze;
|
||||||
mod alt_extend;
|
mod alt_extend;
|
||||||
mod alt_set;
|
mod alt_set;
|
||||||
mod benchmark;
|
mod benchmark;
|
||||||
|
|
|
@ -10,7 +10,11 @@ pub struct PerpCancelAllOrders<'info> {
|
||||||
)]
|
)]
|
||||||
pub group: AccountLoader<'info, Group>,
|
pub group: AccountLoader<'info, Group>,
|
||||||
|
|
||||||
#[account(mut, has_one = group)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
pub owner: Signer<'info>,
|
pub owner: Signer<'info>,
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,11 @@ pub struct PerpCancelAllOrdersBySide<'info> {
|
||||||
)]
|
)]
|
||||||
pub group: AccountLoader<'info, Group>,
|
pub group: AccountLoader<'info, Group>,
|
||||||
|
|
||||||
#[account(mut, has_one = group)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
pub owner: Signer<'info>,
|
pub owner: Signer<'info>,
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,11 @@ pub struct PerpCancelOrder<'info> {
|
||||||
)]
|
)]
|
||||||
pub group: AccountLoader<'info, Group>,
|
pub group: AccountLoader<'info, Group>,
|
||||||
|
|
||||||
#[account(mut, has_one = group)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
pub owner: Signer<'info>,
|
pub owner: Signer<'info>,
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,11 @@ pub struct PerpCancelOrderByClientOrderId<'info> {
|
||||||
)]
|
)]
|
||||||
pub group: AccountLoader<'info, Group>,
|
pub group: AccountLoader<'info, Group>,
|
||||||
|
|
||||||
#[account(mut, has_one = group)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
pub owner: Signer<'info>,
|
pub owner: Signer<'info>,
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,8 @@ pub struct PerpDeactivatePosition<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
// owner is checked at #1
|
// owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
|
@ -26,7 +26,8 @@ pub struct PerpLiqBankruptcy<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = liqor.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
// liqor_owner is checked at #1
|
// liqor_owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub liqor: AccountLoader<'info, MangoAccountFixed>,
|
pub liqor: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
@ -34,7 +35,8 @@ pub struct PerpLiqBankruptcy<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = liqee.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
)]
|
)]
|
||||||
pub liqee: AccountLoader<'info, MangoAccountFixed>,
|
pub liqee: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
||||||
|
|
|
@ -24,13 +24,18 @@ pub struct PerpLiqBasePosition<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = liqor.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
// liqor_owner is checked at #1
|
// liqor_owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub liqor: AccountLoader<'info, MangoAccountFixed>,
|
pub liqor: AccountLoader<'info, MangoAccountFixed>,
|
||||||
pub liqor_owner: Signer<'info>,
|
pub liqor_owner: Signer<'info>,
|
||||||
|
|
||||||
#[account(mut, has_one = group)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
constraint = liqee.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub liqee: AccountLoader<'info, MangoAccountFixed>,
|
pub liqee: AccountLoader<'info, MangoAccountFixed>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,11 @@ pub struct PerpLiqForceCancelOrders<'info> {
|
||||||
)]
|
)]
|
||||||
pub group: AccountLoader<'info, Group>,
|
pub group: AccountLoader<'info, Group>,
|
||||||
|
|
||||||
#[account(mut, has_one = group)]
|
// Allow force cancel even if account is frozen
|
||||||
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
|
|
|
@ -20,13 +20,18 @@ pub struct PerpLiqQuoteAndBankruptcy<'info> {
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group,
|
has_one = group,
|
||||||
|
constraint = liqor.load()?.is_operational() @ MangoError::AccountIsFrozen,
|
||||||
// liqor_owner is checked at #1
|
// liqor_owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub liqor: AccountLoader<'info, MangoAccountFixed>,
|
pub liqor: AccountLoader<'info, MangoAccountFixed>,
|
||||||
pub liqor_owner: Signer<'info>,
|
pub liqor_owner: Signer<'info>,
|
||||||
|
|
||||||
// This account MUST have a loss
|
// This account MUST have a loss
|
||||||
#[account(mut, has_one = group)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
constraint = liqee.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub liqee: AccountLoader<'info, MangoAccountFixed>,
|
pub liqee: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
||||||
#[account(mut, has_one = group, has_one = oracle)]
|
#[account(mut, has_one = group, has_one = oracle)]
|
||||||
|
|
|
@ -16,7 +16,11 @@ pub struct PerpPlaceOrder<'info> {
|
||||||
)]
|
)]
|
||||||
pub group: AccountLoader<'info, Group>,
|
pub group: AccountLoader<'info, Group>,
|
||||||
|
|
||||||
#[account(mut, has_one = group)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
pub owner: Signer<'info>,
|
pub owner: Signer<'info>,
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,11 @@ pub struct PerpSettleFees<'info> {
|
||||||
pub perp_market: AccountLoader<'info, PerpMarket>,
|
pub perp_market: AccountLoader<'info, PerpMarket>,
|
||||||
|
|
||||||
// This account MUST have a loss
|
// This account MUST have a loss
|
||||||
#[account(mut, has_one = group)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
||||||
/// CHECK: Oracle can have different account types, constrained by address in perp_market
|
/// CHECK: Oracle can have different account types, constrained by address in perp_market
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub struct PerpSettlePnl<'info> {
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group,
|
has_one = group,
|
||||||
|
constraint = settler.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
// settler_owner is checked at #1
|
// settler_owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub settler: AccountLoader<'info, MangoAccountFixed>,
|
pub settler: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
@ -28,10 +29,17 @@ pub struct PerpSettlePnl<'info> {
|
||||||
pub perp_market: AccountLoader<'info, PerpMarket>,
|
pub perp_market: AccountLoader<'info, PerpMarket>,
|
||||||
|
|
||||||
// This account MUST be profitable
|
// This account MUST be profitable
|
||||||
#[account(mut, has_one = group)]
|
#[account(mut,
|
||||||
|
has_one = group,
|
||||||
|
constraint = account_a.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account_a: AccountLoader<'info, MangoAccountFixed>,
|
pub account_a: AccountLoader<'info, MangoAccountFixed>,
|
||||||
// This account MUST have a loss
|
// This account MUST have a loss
|
||||||
#[account(mut, has_one = group)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
constraint = account_b.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account_b: AccountLoader<'info, MangoAccountFixed>,
|
pub account_b: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
||||||
/// CHECK: Oracle can have different account types, constrained by address in perp_market
|
/// CHECK: Oracle can have different account types, constrained by address in perp_market
|
||||||
|
|
|
@ -14,7 +14,8 @@ pub struct Serum3CancelAllOrders<'info> {
|
||||||
pub group: AccountLoader<'info, Group>,
|
pub group: AccountLoader<'info, Group>,
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
// owner is checked at #1
|
// owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
|
@ -20,7 +20,8 @@ pub struct Serum3CancelOrder<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
// owner is checked at #1
|
// owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
|
@ -12,7 +12,8 @@ pub struct Serum3CloseOpenOrders<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
// owner is checked at #1
|
// owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
|
@ -12,7 +12,8 @@ pub struct Serum3CreateOpenOrders<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
// owner is checked at #1
|
// owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
|
@ -19,7 +19,11 @@ pub struct Serum3LiqForceCancelOrders<'info> {
|
||||||
)]
|
)]
|
||||||
pub group: AccountLoader<'info, Group>,
|
pub group: AccountLoader<'info, Group>,
|
||||||
|
|
||||||
#[account(mut, has_one = group)]
|
// Allow force cancel even if account is frozen
|
||||||
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
||||||
#[account(mut)]
|
#[account(mut)]
|
||||||
|
|
|
@ -142,7 +142,8 @@ pub struct Serum3PlaceOrder<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
// owner is checked at #1
|
// owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
|
@ -20,7 +20,8 @@ pub struct Serum3SettleFunds<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
// owner is checked at #1
|
// owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
|
@ -20,7 +20,11 @@ pub struct TokenDepositIntoExisting<'info> {
|
||||||
)]
|
)]
|
||||||
pub group: AccountLoader<'info, Group>,
|
pub group: AccountLoader<'info, Group>,
|
||||||
|
|
||||||
#[account(mut, has_one = group)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
|
@ -53,7 +57,12 @@ pub struct TokenDeposit<'info> {
|
||||||
)]
|
)]
|
||||||
pub group: AccountLoader<'info, Group>,
|
pub group: AccountLoader<'info, Group>,
|
||||||
|
|
||||||
#[account(mut, has_one = group, has_one = owner)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
has_one = owner,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
pub owner: Signer<'info>,
|
pub owner: Signer<'info>,
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ pub struct TokenLiqBankruptcy<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = liqor.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
// liqor_owner is checked at #1
|
// liqor_owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub liqor: AccountLoader<'info, MangoAccountFixed>,
|
pub liqor: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
@ -36,7 +37,8 @@ pub struct TokenLiqBankruptcy<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = liqee.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
)]
|
)]
|
||||||
pub liqee: AccountLoader<'info, MangoAccountFixed>,
|
pub liqee: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,8 @@ pub struct TokenLiqWithToken<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = liqor.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
// liqor_owner is checked at #1
|
// liqor_owner is checked at #1
|
||||||
)]
|
)]
|
||||||
pub liqor: AccountLoader<'info, MangoAccountFixed>,
|
pub liqor: AccountLoader<'info, MangoAccountFixed>,
|
||||||
|
@ -28,7 +29,8 @@ pub struct TokenLiqWithToken<'info> {
|
||||||
|
|
||||||
#[account(
|
#[account(
|
||||||
mut,
|
mut,
|
||||||
has_one = group
|
has_one = group,
|
||||||
|
constraint = liqee.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
)]
|
)]
|
||||||
pub liqee: AccountLoader<'info, MangoAccountFixed>,
|
pub liqee: AccountLoader<'info, MangoAccountFixed>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,12 @@ pub struct TokenWithdraw<'info> {
|
||||||
)]
|
)]
|
||||||
pub group: AccountLoader<'info, Group>,
|
pub group: AccountLoader<'info, Group>,
|
||||||
|
|
||||||
#[account(mut, has_one = group, has_one = owner)]
|
#[account(
|
||||||
|
mut,
|
||||||
|
has_one = group,
|
||||||
|
has_one = owner,
|
||||||
|
constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen
|
||||||
|
)]
|
||||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||||
pub owner: Signer<'info>,
|
pub owner: Signer<'info>,
|
||||||
|
|
||||||
|
|
|
@ -222,6 +222,10 @@ pub mod mango_v4 {
|
||||||
instructions::account_edit(ctx, name_opt, delegate_opt)
|
instructions::account_edit(ctx, name_opt, delegate_opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn aaccount_toggle_freeze(ctx: Context<AccountToggleFreeze>, freeze: bool) -> Result<()> {
|
||||||
|
instructions::account_toggle_freeze(ctx, freeze)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn account_close(ctx: Context<AccountClose>, force_close: bool) -> Result<()> {
|
pub fn account_close(ctx: Context<AccountClose>, force_close: bool) -> Result<()> {
|
||||||
instructions::account_close(ctx, force_close)
|
instructions::account_close(ctx, force_close)
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,9 @@ pub struct MangoAccount {
|
||||||
/// Init health as calculated during HealthReginBegin, rounded up.
|
/// Init health as calculated during HealthReginBegin, rounded up.
|
||||||
pub health_region_begin_init_health: i64,
|
pub health_region_begin_init_health: i64,
|
||||||
|
|
||||||
pub reserved: [u8; 240],
|
pub frozen_until: i64,
|
||||||
|
|
||||||
|
pub reserved: [u8; 232],
|
||||||
|
|
||||||
// dynamic
|
// dynamic
|
||||||
pub header_version: u8,
|
pub header_version: u8,
|
||||||
|
@ -120,7 +122,8 @@ impl MangoAccount {
|
||||||
padding: Default::default(),
|
padding: Default::default(),
|
||||||
net_deposits: 0,
|
net_deposits: 0,
|
||||||
health_region_begin_init_health: 0,
|
health_region_begin_init_health: 0,
|
||||||
reserved: [0; 240],
|
frozen_until: 0,
|
||||||
|
reserved: [0; 232],
|
||||||
header_version: DEFAULT_MANGO_ACCOUNT_VERSION,
|
header_version: DEFAULT_MANGO_ACCOUNT_VERSION,
|
||||||
padding3: Default::default(),
|
padding3: Default::default(),
|
||||||
padding4: Default::default(),
|
padding4: Default::default(),
|
||||||
|
@ -201,9 +204,10 @@ pub struct MangoAccountFixed {
|
||||||
pub net_deposits: i64,
|
pub net_deposits: i64,
|
||||||
pub perp_spot_transfers: i64,
|
pub perp_spot_transfers: i64,
|
||||||
pub health_region_begin_init_health: i64,
|
pub health_region_begin_init_health: i64,
|
||||||
pub reserved: [u8; 240],
|
pub frozen_until: u64,
|
||||||
|
pub reserved: [u8; 232],
|
||||||
}
|
}
|
||||||
const_assert_eq!(size_of::<MangoAccountFixed>(), 32 * 4 + 8 + 3 * 8 + 240);
|
const_assert_eq!(size_of::<MangoAccountFixed>(), 32 * 4 + 8 + 3 * 8 + 8 + 232);
|
||||||
const_assert_eq!(size_of::<MangoAccountFixed>(), 400);
|
const_assert_eq!(size_of::<MangoAccountFixed>(), 400);
|
||||||
const_assert_eq!(size_of::<MangoAccountFixed>() % 8, 0);
|
const_assert_eq!(size_of::<MangoAccountFixed>() % 8, 0);
|
||||||
|
|
||||||
|
@ -214,6 +218,11 @@ impl MangoAccountFixed {
|
||||||
.trim_matches(char::from(0))
|
.trim_matches(char::from(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_operational(&self) -> bool {
|
||||||
|
let now_ts: u64 = Clock::get().unwrap().unix_timestamp.try_into().unwrap();
|
||||||
|
self.frozen_until < now_ts
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_owner_or_delegate(&self, ix_signer: Pubkey) -> bool {
|
pub fn is_owner_or_delegate(&self, ix_signer: Pubkey) -> bool {
|
||||||
self.owner == ix_signer || self.delegate == ix_signer
|
self.owner == ix_signer || self.delegate == ix_signer
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ export class Group {
|
||||||
insuranceVault: PublicKey;
|
insuranceVault: PublicKey;
|
||||||
testing: number;
|
testing: number;
|
||||||
version: number;
|
version: number;
|
||||||
|
halted: number;
|
||||||
addressLookupTables: PublicKey[];
|
addressLookupTables: PublicKey[];
|
||||||
},
|
},
|
||||||
): Group {
|
): Group {
|
||||||
|
@ -47,6 +48,7 @@ export class Group {
|
||||||
obj.insuranceVault,
|
obj.insuranceVault,
|
||||||
obj.testing,
|
obj.testing,
|
||||||
obj.version,
|
obj.version,
|
||||||
|
obj.halted,
|
||||||
obj.addressLookupTables,
|
obj.addressLookupTables,
|
||||||
[], // addressLookupTablesList
|
[], // addressLookupTablesList
|
||||||
new Map(), // banksMapByName
|
new Map(), // banksMapByName
|
||||||
|
@ -74,6 +76,7 @@ export class Group {
|
||||||
public insuranceVault: PublicKey,
|
public insuranceVault: PublicKey,
|
||||||
public testing: number,
|
public testing: number,
|
||||||
public version: number,
|
public version: number,
|
||||||
|
public halted: number,
|
||||||
public addressLookupTables: PublicKey[],
|
public addressLookupTables: PublicKey[],
|
||||||
public addressLookupTablesList: AddressLookupTableAccount[],
|
public addressLookupTablesList: AddressLookupTableAccount[],
|
||||||
public banksMapByName: Map<string, Bank[]>,
|
public banksMapByName: Map<string, Bank[]>,
|
||||||
|
@ -90,6 +93,10 @@ export class Group {
|
||||||
public vaultAmountsMap: Map<string, BN>,
|
public vaultAmountsMap: Map<string, BN>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
public isOperational(): boolean {
|
||||||
|
return this.halted === 0;
|
||||||
|
}
|
||||||
|
|
||||||
public async reloadAll(client: MangoClient, ids?: Id): Promise<void> {
|
public async reloadAll(client: MangoClient, ids?: Id): Promise<void> {
|
||||||
// console.time('group.reload');
|
// console.time('group.reload');
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
|
|
|
@ -31,6 +31,7 @@ export class MangoAccount {
|
||||||
netDeposits: BN;
|
netDeposits: BN;
|
||||||
perpSpotTransfers: BN;
|
perpSpotTransfers: BN;
|
||||||
healthRegionBeginInitHealth: BN;
|
healthRegionBeginInitHealth: BN;
|
||||||
|
frozenUntil: BN;
|
||||||
headerVersion: number;
|
headerVersion: number;
|
||||||
tokens: unknown;
|
tokens: unknown;
|
||||||
serum3: unknown;
|
serum3: unknown;
|
||||||
|
@ -50,6 +51,7 @@ export class MangoAccount {
|
||||||
obj.netDeposits,
|
obj.netDeposits,
|
||||||
obj.perpSpotTransfers,
|
obj.perpSpotTransfers,
|
||||||
obj.healthRegionBeginInitHealth,
|
obj.healthRegionBeginInitHealth,
|
||||||
|
obj.frozenUntil,
|
||||||
obj.headerVersion,
|
obj.headerVersion,
|
||||||
obj.tokens as TokenPositionDto[],
|
obj.tokens as TokenPositionDto[],
|
||||||
obj.serum3 as Serum3PositionDto[],
|
obj.serum3 as Serum3PositionDto[],
|
||||||
|
@ -71,6 +73,7 @@ export class MangoAccount {
|
||||||
public netDeposits: BN,
|
public netDeposits: BN,
|
||||||
public perpSpotTransfers: BN,
|
public perpSpotTransfers: BN,
|
||||||
public healthRegionBeginInitHealth: BN,
|
public healthRegionBeginInitHealth: BN,
|
||||||
|
public frozenUntil: BN,
|
||||||
public headerVersion: number,
|
public headerVersion: number,
|
||||||
tokens: TokenPositionDto[],
|
tokens: TokenPositionDto[],
|
||||||
serum3: Serum3PositionDto[],
|
serum3: Serum3PositionDto[],
|
||||||
|
@ -134,6 +137,10 @@ export class MangoAccount {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isOperational(): boolean {
|
||||||
|
return this.frozenUntil.lt(new BN(Date.now() / 1000));
|
||||||
|
}
|
||||||
|
|
||||||
public tokensActive(): TokenPosition[] {
|
public tokensActive(): TokenPosition[] {
|
||||||
return this.tokens.filter((token) => token.isActive());
|
return this.tokens.filter((token) => token.isActive());
|
||||||
}
|
}
|
||||||
|
|
|
@ -671,6 +671,21 @@ export class MangoClient {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async toggleMangoAccountFreeze(
|
||||||
|
group: Group,
|
||||||
|
mangoAccount: MangoAccount,
|
||||||
|
freeze: boolean,
|
||||||
|
): Promise<TransactionSignature> {
|
||||||
|
return await this.program.methods
|
||||||
|
.aaccountToggleFreeze(freeze)
|
||||||
|
.accounts({
|
||||||
|
group: group.publicKey,
|
||||||
|
account: mangoAccount.publicKey,
|
||||||
|
admin: (this.program.provider as AnchorProvider).wallet.publicKey,
|
||||||
|
})
|
||||||
|
.rpc();
|
||||||
|
}
|
||||||
|
|
||||||
public async getMangoAccount(
|
public async getMangoAccount(
|
||||||
mangoAccount: MangoAccount | PublicKey,
|
mangoAccount: MangoAccount | PublicKey,
|
||||||
): Promise<MangoAccount> {
|
): Promise<MangoAccount> {
|
||||||
|
|
|
@ -1022,6 +1022,32 @@ export type MangoV4 = {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "aaccountToggleFreeze",
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "group",
|
||||||
|
"isMut": false,
|
||||||
|
"isSigner": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "account",
|
||||||
|
"isMut": true,
|
||||||
|
"isSigner": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "admin",
|
||||||
|
"isMut": false,
|
||||||
|
"isSigner": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "freeze",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "accountClose",
|
"name": "accountClose",
|
||||||
"accounts": [
|
"accounts": [
|
||||||
|
@ -4002,12 +4028,16 @@ export type MangoV4 = {
|
||||||
],
|
],
|
||||||
"type": "i64"
|
"type": "i64"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "frozenUntil",
|
||||||
|
"type": "i64"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "reserved",
|
"name": "reserved",
|
||||||
"type": {
|
"type": {
|
||||||
"array": [
|
"array": [
|
||||||
"u8",
|
"u8",
|
||||||
240
|
232
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5425,12 +5455,16 @@ export type MangoV4 = {
|
||||||
"name": "healthRegionBeginInitHealth",
|
"name": "healthRegionBeginInitHealth",
|
||||||
"type": "i64"
|
"type": "i64"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "frozenUntil",
|
||||||
|
"type": "u64"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "reserved",
|
"name": "reserved",
|
||||||
"type": {
|
"type": {
|
||||||
"array": [
|
"array": [
|
||||||
"u8",
|
"u8",
|
||||||
240
|
232
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7673,6 +7707,11 @@ export type MangoV4 = {
|
||||||
"code": 6037,
|
"code": 6037,
|
||||||
"name": "HasLiquidatableTrustedPerpPnl",
|
"name": "HasLiquidatableTrustedPerpPnl",
|
||||||
"msg": "has liquidatable trusted perp pnl"
|
"msg": "has liquidatable trusted perp pnl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 6038,
|
||||||
|
"name": "AccountIsFrozen",
|
||||||
|
"msg": "account is frozen"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
@ -8701,6 +8740,32 @@ export const IDL: MangoV4 = {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "aaccountToggleFreeze",
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "group",
|
||||||
|
"isMut": false,
|
||||||
|
"isSigner": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "account",
|
||||||
|
"isMut": true,
|
||||||
|
"isSigner": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "admin",
|
||||||
|
"isMut": false,
|
||||||
|
"isSigner": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "freeze",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "accountClose",
|
"name": "accountClose",
|
||||||
"accounts": [
|
"accounts": [
|
||||||
|
@ -11681,12 +11746,16 @@ export const IDL: MangoV4 = {
|
||||||
],
|
],
|
||||||
"type": "i64"
|
"type": "i64"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "frozenUntil",
|
||||||
|
"type": "i64"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "reserved",
|
"name": "reserved",
|
||||||
"type": {
|
"type": {
|
||||||
"array": [
|
"array": [
|
||||||
"u8",
|
"u8",
|
||||||
240
|
232
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -13104,12 +13173,16 @@ export const IDL: MangoV4 = {
|
||||||
"name": "healthRegionBeginInitHealth",
|
"name": "healthRegionBeginInitHealth",
|
||||||
"type": "i64"
|
"type": "i64"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "frozenUntil",
|
||||||
|
"type": "u64"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "reserved",
|
"name": "reserved",
|
||||||
"type": {
|
"type": {
|
||||||
"array": [
|
"array": [
|
||||||
"u8",
|
"u8",
|
||||||
240
|
232
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15352,6 +15425,11 @@ export const IDL: MangoV4 = {
|
||||||
"code": 6037,
|
"code": 6037,
|
||||||
"name": "HasLiquidatableTrustedPerpPnl",
|
"name": "HasLiquidatableTrustedPerpPnl",
|
||||||
"msg": "has liquidatable trusted perp pnl"
|
"msg": "has liquidatable trusted perp pnl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 6038,
|
||||||
|
"name": "AccountIsFrozen",
|
||||||
|
"msg": "account is frozen"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue