diff --git a/programs/mango-v4/src/instructions/account_close.rs b/programs/mango-v4/src/instructions/account_close.rs index 7572aa149..ee7e34c23 100644 --- a/programs/mango-v4/src/instructions/account_close.rs +++ b/programs/mango-v4/src/instructions/account_close.rs @@ -24,13 +24,14 @@ pub struct AccountClose<'info> { pub token_program: Program<'info, Token>, } -pub fn account_close(ctx: Context) -> Result<()> { - let group = ctx.accounts.group.load()?; - +pub fn account_close(ctx: Context, force_close: bool) -> Result<()> { let account = ctx.accounts.account.load_mut()?; - // don't perform checks if group is just testing - if !group.is_testing() { + if !ctx.accounts.group.load()?.is_testing() { + require!(!force_close, MangoError::SomeError); + } + + if !force_close { require!(!account.fixed.being_liquidated(), MangoError::SomeError); for ele in account.all_token_positions() { require_eq!(ele.is_active(), false); diff --git a/programs/mango-v4/src/lib.rs b/programs/mango-v4/src/lib.rs index 2fa5426e4..436ccd532 100644 --- a/programs/mango-v4/src/lib.rs +++ b/programs/mango-v4/src/lib.rs @@ -214,8 +214,8 @@ pub mod mango_v4 { instructions::account_edit(ctx, name_opt, delegate_opt) } - pub fn account_close(ctx: Context) -> Result<()> { - instructions::account_close(ctx) + pub fn account_close(ctx: Context, force_close: bool) -> Result<()> { + instructions::account_close(ctx, force_close) } // todo: diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index 7e62a9643..8ec17acfe 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -763,12 +763,22 @@ export class MangoClient { }); } + /** + * Note: this ix doesn't settle liabs, reduce open positions, or withdraw tokens to wallet, + * it simply closes the account. To close successfully ensure all positions are closed, or + * use forceClose flag + * @param group + * @param mangoAccount + * @param forceClose + * @returns + */ public async closeMangoAccount( group: Group, mangoAccount: MangoAccount, + forceClose = false, ): Promise { const ix = await this.program.methods - .accountClose() + .accountClose(forceClose) .accounts({ group: group.publicKey, account: mangoAccount.publicKey, diff --git a/ts/client/src/mango_v4.ts b/ts/client/src/mango_v4.ts index 42e250208..dcb2f1525 100644 --- a/ts/client/src/mango_v4.ts +++ b/ts/client/src/mango_v4.ts @@ -1018,7 +1018,12 @@ export type MangoV4 = { "isSigner": false } ], - "args": [] + "args": [ + { + "name": "forceClose", + "type": "bool" + } + ] }, { "name": "stubOracleCreate", @@ -4403,7 +4408,8 @@ export type MangoV4 = { { "name": "settlePnlLimitFactor", "docs": [ - "Fraction of perp base value that can be settled each window.", + "Fraction of perp base value (i.e. base_lots * entry_price_in_lots) of unrealized", + "positive pnl that can be settled each window.", "Set to a negative value to disable the limit." ], "type": "f32" @@ -8421,7 +8427,12 @@ export const IDL: MangoV4 = { "isSigner": false } ], - "args": [] + "args": [ + { + "name": "forceClose", + "type": "bool" + } + ] }, { "name": "stubOracleCreate", @@ -11806,7 +11817,8 @@ export const IDL: MangoV4 = { { "name": "settlePnlLimitFactor", "docs": [ - "Fraction of perp base value that can be settled each window.", + "Fraction of perp base value (i.e. base_lots * entry_price_in_lots) of unrealized", + "positive pnl that can be settled each window.", "Set to a negative value to disable the limit." ], "type": "f32" diff --git a/ts/client/src/scripts/mb-liqtest-settle-and-close-all.ts b/ts/client/src/scripts/mb-liqtest-settle-and-close-all.ts index 08b30bf53..886938074 100644 --- a/ts/client/src/scripts/mb-liqtest-settle-and-close-all.ts +++ b/ts/client/src/scripts/mb-liqtest-settle-and-close-all.ts @@ -80,7 +80,7 @@ async function main() { // close account try { console.log(`closing account: ${account}`); - await client.closeMangoAccount(group, account); + await client.closeMangoAccount(group, account, true); } catch (error) { console.log(`failed to close ${account.publicKey}: ${error}`); }