From f5cb67fb3b4914c7bf7e5adc18164b039a8dc102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezin=CC=81ski?= Date: Thu, 12 Jan 2023 22:34:48 +0100 Subject: [PATCH 1/9] start of close --- ts/client/src/client.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index 4d8d067ca..6752ff1d6 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -829,6 +829,28 @@ export class MangoClient { ); } + //withdraw all assets, close oo, deactivating perp positions, close account + public async totalCloseMangoAccount( + group: Group, + mangoAccount: MangoAccount, + forceClose = false, + ): Promise { + const ix = await this.program.methods + .accountClose(forceClose) + .accounts({ + group: group.publicKey, + account: mangoAccount.publicKey, + owner: (this.program.provider as AnchorProvider).wallet.publicKey, + solDestination: mangoAccount.owner, + }) + .instruction(); + + return await this.sendAndConfirmTransaction( + [ix], + group.addressLookupTablesList, + ); + } + public async tokenDeposit( group: Group, mangoAccount: MangoAccount, From 6e3e72436f90c997b8f454a61d4199cbcf322268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezin=CC=81ski?= Date: Fri, 13 Jan 2023 01:38:02 +0100 Subject: [PATCH 2/9] withdraw --- ts/client/src/client.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index 6752ff1d6..27e96d613 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -830,7 +830,7 @@ export class MangoClient { } //withdraw all assets, close oo, deactivating perp positions, close account - public async totalCloseMangoAccount( + public async emptyAndCloseMangoAccount( group: Group, mangoAccount: MangoAccount, forceClose = false, @@ -959,22 +959,27 @@ export class MangoClient { allowBorrow: boolean, ): Promise { const nativeAmount = toNative(amount, group.getMintDecimals(mintPk)); - return await this.tokenWithdrawNative( + const ixes = await this.tokenWithdrawNativeIx( group, mangoAccount, mintPk, nativeAmount, allowBorrow, ); + + return await this.sendAndConfirmTransaction( + [...ixes], + group.addressLookupTablesList, + ); } - public async tokenWithdrawNative( + public async tokenWithdrawNativeIx( group: Group, mangoAccount: MangoAccount, mintPk: PublicKey, nativeAmount: BN, allowBorrow: boolean, - ): Promise { + ): Promise { const bank = group.getFirstBankByMint(mintPk); const tokenAccountPk = await getAssociatedTokenAddress( @@ -1030,10 +1035,7 @@ export class MangoClient { ) .instruction(); - return await this.sendAndConfirmTransaction( - [...preInstructions, ix, ...postInstructions], - group.addressLookupTablesList, - ); + return [...preInstructions, ix, ...postInstructions]; } // Serum From 80cf41ff5f9c08f581195c492a0696c8d82e0942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezin=CC=81ski?= Date: Fri, 13 Jan 2023 13:19:04 +0100 Subject: [PATCH 3/9] empty and close mango account --- ts/client/src/client.ts | 62 +++++++++++++++++-- .../src/scripts/devnet-user-close-account.ts | 6 +- ts/client/src/scripts/mb-close-account.ts | 6 +- .../src/scripts/mb-liqtest-make-candidates.ts | 12 +++- 4 files changed, 76 insertions(+), 10 deletions(-) diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index 27e96d613..95598e7da 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -829,13 +829,46 @@ export class MangoClient { ); } - //withdraw all assets, close oo, deactivating perp positions, close account public async emptyAndCloseMangoAccount( group: Group, mangoAccount: MangoAccount, forceClose = false, ): Promise { - const ix = await this.program.methods + const instructions: TransactionInstruction[] = []; + for (const token of mangoAccount.tokensActive()) { + const bank = group.getFirstBankByTokenIndex(token.tokenIndex); + const withdrawIx = await this.tokenWithdrawNativeIx( + group, + mangoAccount, + bank.mint, + new BN(token.balance(bank).toNumber()), + false, + ); + instructions.push(...withdrawIx); + } + + for (const serum3Account of mangoAccount.serum3Active()) { + const serum3Market = group.serum3MarketsMapByMarketIndex.get( + serum3Account.marketIndex, + )!.serumMarketExternal!; + const closeOOIx = await this.serum3CloseOpenOrdersIx( + group, + mangoAccount, + serum3Market, + ); + instructions.push(closeOOIx); + } + + for (const perp of mangoAccount.perpActive()) { + const deactivatingPositionIx = await this.perpDeactivatePositionIx( + group, + mangoAccount, + perp.marketIndex, + ); + instructions.push(deactivatingPositionIx); + } + + const closeIx = await this.program.methods .accountClose(forceClose) .accounts({ group: group.publicKey, @@ -844,9 +877,10 @@ export class MangoClient { solDestination: mangoAccount.owner, }) .instruction(); + instructions.push(closeIx); return await this.sendAndConfirmTransaction( - [ix], + [...instructions], group.addressLookupTablesList, ); } @@ -1783,11 +1817,11 @@ export class MangoClient { ); } - public async perpDeactivatePosition( + public async perpDeactivatePositionIx( group: Group, mangoAccount: MangoAccount, perpMarketIndex: PerpMarketIndex, - ): Promise { + ): Promise { const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex); const healthRemainingAccounts: PublicKey[] = this.buildHealthRemainingAccounts( @@ -1811,7 +1845,23 @@ export class MangoClient { ({ pubkey: pk, isWritable: false, isSigner: false } as AccountMeta), ), ) - .rpc(); + .instruction(); + } + + public async perpDeactivatePosition( + group: Group, + mangoAccount: MangoAccount, + perpMarketIndex: PerpMarketIndex, + ): Promise { + const ix = await this.perpDeactivatePositionIx( + group, + mangoAccount, + perpMarketIndex, + ); + return await this.sendAndConfirmTransaction( + [ix], + group.addressLookupTablesList, + ); } public async perpPlaceOrder( diff --git a/ts/client/src/scripts/devnet-user-close-account.ts b/ts/client/src/scripts/devnet-user-close-account.ts index cb6ad9f24..292a23166 100644 --- a/ts/client/src/scripts/devnet-user-close-account.ts +++ b/ts/client/src/scripts/devnet-user-close-account.ts @@ -114,7 +114,7 @@ async function main() { } native amount ${nativeFlooredNumber} `, ); - await client.tokenWithdrawNative( + const withdrawIx = await client.tokenWithdrawNativeIx( group, mangoAccount, group.getFirstBankByTokenIndex(token.tokenIndex).mint, @@ -123,6 +123,10 @@ async function main() { ) /* see comment in token_withdraw in program */, false, ); + await this.sendAndConfirmTransaction( + [...withdrawIx], + group.addressLookupTablesList, + ); } // reload and print current positions diff --git a/ts/client/src/scripts/mb-close-account.ts b/ts/client/src/scripts/mb-close-account.ts index 9ae717f6d..49f21f75e 100644 --- a/ts/client/src/scripts/mb-close-account.ts +++ b/ts/client/src/scripts/mb-close-account.ts @@ -99,7 +99,7 @@ async function closeUserAccount(userKeypairFile: string) { continue; } - await client.tokenWithdrawNative( + const withdrawIx = await client.tokenWithdrawNativeIx( group, mangoAccount, group.getFirstBankByTokenIndex(token.tokenIndex)!.mint, @@ -110,6 +110,10 @@ async function closeUserAccount(userKeypairFile: string) { ), false, ); + await this.sendAndConfirmTransaction( + [...withdrawIx], + group.addressLookupTablesList, + ); } } catch (error) { console.log(error); diff --git a/ts/client/src/scripts/mb-liqtest-make-candidates.ts b/ts/client/src/scripts/mb-liqtest-make-candidates.ts index ef8d931e3..b0d21c50d 100644 --- a/ts/client/src/scripts/mb-liqtest-make-candidates.ts +++ b/ts/client/src/scripts/mb-liqtest-make-candidates.ts @@ -192,13 +192,17 @@ async function main() { try { await setBankPrice(bank, PRICES[liabName] / 2); - await client.tokenWithdrawNative( + const withdrawIx = await client.tokenWithdrawNativeIx( group, mangoAccount, liabMint, new BN(liabAmount), true, ); + await this.sendAndConfirmTransaction( + [...withdrawIx], + group.addressLookupTablesList, + ); } finally { // restore the oracle await setBankPrice(bank, PRICES[liabName]); @@ -446,13 +450,17 @@ async function main() { await setBankPrice(collateralBank, PRICES['SOL'] * 10); // Spot-borrow more than the collateral is worth - await client.tokenWithdrawNative( + const withdrawIx = await client.tokenWithdrawNativeIx( group, mangoAccount, liabMint, new BN(-5000), true, ); + await this.sendAndConfirmTransaction( + [...withdrawIx], + group.addressLookupTablesList, + ); await mangoAccount.reload(client); // Execute two trades that leave the account with +$0.011 positive pnl From 001a528a6eb6c38a5bd3c14ea550a8fa34c5e6ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezin=CC=81ski?= Date: Fri, 13 Jan 2023 17:33:24 +0100 Subject: [PATCH 4/9] fix --- ts/client/src/client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index 95598e7da..1022375ab 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -1049,7 +1049,7 @@ export class MangoClient { [bank], [], ); - + console.log(healthRemainingAccounts, '@@@'); const ix = await this.program.methods .tokenWithdraw(new BN(nativeAmount), allowBorrow) .accounts({ @@ -2709,7 +2709,7 @@ export class MangoClient { } } } - + console.log(tokenPositionIndices); const mintInfos = tokenPositionIndices .filter((tokenIndex) => tokenIndex !== TokenPosition.TokenIndexUnset) .map((tokenIndex) => group.mintInfosMapByTokenIndex.get(tokenIndex)!); From c459c09451e99c1d285ede1fe7f8fe61d6f8f6b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezin=CC=81ski?= Date: Fri, 13 Jan 2023 18:07:13 +0100 Subject: [PATCH 5/9] fixes --- ts/client/src/client.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index 097765062..3a3a43b5a 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -837,14 +837,17 @@ export class MangoClient { const instructions: TransactionInstruction[] = []; for (const token of mangoAccount.tokensActive()) { const bank = group.getFirstBankByTokenIndex(token.tokenIndex); - const withdrawIx = await this.tokenWithdrawNativeIx( - group, - mangoAccount, - bank.mint, - new BN(token.balance(bank).toNumber()), - false, - ); - instructions.push(...withdrawIx); + const nativeAmount = token.balance(bank).data; + if (!nativeAmount.isZero()) { + const withdrawIx = await this.tokenWithdrawNativeIx( + group, + mangoAccount, + bank.mint, + nativeAmount, + false, + ); + instructions.push(...withdrawIx); + } } for (const serum3Account of mangoAccount.serum3Active()) { @@ -1049,7 +1052,7 @@ export class MangoClient { [bank], [], ); - console.log(healthRemainingAccounts, '@@@'); + const ix = await this.program.methods .tokenWithdraw(new BN(nativeAmount), allowBorrow) .accounts({ @@ -2707,7 +2710,6 @@ export class MangoClient { } } } - console.log(tokenPositionIndices); const mintInfos = tokenPositionIndices .filter((tokenIndex) => tokenIndex !== TokenPosition.TokenIndexUnset) .map((tokenIndex) => group.mintInfosMapByTokenIndex.get(tokenIndex)!); From 448cdf7c09f7192679f71971e9052a32de54d2ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezin=CC=81ski?= Date: Fri, 13 Jan 2023 18:54:25 +0100 Subject: [PATCH 6/9] fix --- ts/client/src/client.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index 3a3a43b5a..a4595d282 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -55,6 +55,7 @@ import { createAssociatedTokenAccountIdempotentInstruction, getAssociatedTokenAddress, toNative, + U64_MAX_BN, } from './utils'; import { sendTransaction } from './utils/rpc'; @@ -837,17 +838,14 @@ export class MangoClient { const instructions: TransactionInstruction[] = []; for (const token of mangoAccount.tokensActive()) { const bank = group.getFirstBankByTokenIndex(token.tokenIndex); - const nativeAmount = token.balance(bank).data; - if (!nativeAmount.isZero()) { - const withdrawIx = await this.tokenWithdrawNativeIx( - group, - mangoAccount, - bank.mint, - nativeAmount, - false, - ); - instructions.push(...withdrawIx); - } + const withdrawIx = await this.tokenWithdrawNativeIx( + group, + mangoAccount, + bank.mint, + U64_MAX_BN, + false, + ); + instructions.push(...withdrawIx); } for (const serum3Account of mangoAccount.serum3Active()) { From e3bf0adca21b109ee936fec7ad2ef2da71a50fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezin=CC=81ski?= Date: Fri, 13 Jan 2023 18:59:22 +0100 Subject: [PATCH 7/9] fix --- ts/client/src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index a4595d282..4ec7eb975 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -955,7 +955,7 @@ export class MangoClient { AccountRetriever.Fixed, group, [mangoAccount], - [bank], + [], [], ); From d2b8d76ab660a5c0aab9d5030d3ba474cde46717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezin=CC=81ski?= Date: Fri, 13 Jan 2023 23:32:12 +0100 Subject: [PATCH 8/9] fix --- ts/client/src/client.ts | 93 ++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 29 deletions(-) diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index 4ec7eb975..6535a223b 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -833,44 +833,67 @@ export class MangoClient { public async emptyAndCloseMangoAccount( group: Group, mangoAccount: MangoAccount, - forceClose = false, ): Promise { const instructions: TransactionInstruction[] = []; - for (const token of mangoAccount.tokensActive()) { + const healthAccountsToExclude: PublicKey[] = []; + + for (const serum3Account of mangoAccount.serum3Active()) { + const serum3Market = group.serum3MarketsMapByMarketIndex.get( + serum3Account.marketIndex, + )!; + + const openOrders = mangoAccount.serum3.find( + (account) => account.marketIndex === serum3Market.marketIndex, + )!.openOrders; + + const closeOOIx = await this.serum3CloseOpenOrdersIx( + group, + mangoAccount, + serum3Market.serumMarketExternal, + ); + healthAccountsToExclude.push(openOrders); + instructions.push(closeOOIx); + } + + for (const perp of mangoAccount.perpActive()) { + const perpMarketIndex = perp.marketIndex; + const perpMarket = group.getPerpMarketByMarketIndex(perpMarketIndex); + const deactivatingPositionIx = await this.perpDeactivatePositionIx( + group, + mangoAccount, + perpMarketIndex, + ); + healthAccountsToExclude.push(perpMarket.publicKey); + instructions.push(deactivatingPositionIx); + } + + for (const index in mangoAccount.tokensActive()) { + const indexNum = Number(index); + const accountsToExclude = [...healthAccountsToExclude]; + const token = mangoAccount.tokensActive()[indexNum]; const bank = group.getFirstBankByTokenIndex(token.tokenIndex); + //to withdraw from all token accounts we need to exclude previous tokens pubkeys + //used to build health remaining accounts + if (indexNum !== 0) { + for (let i = indexNum; i--; i >= 0) { + const prevToken = mangoAccount.tokensActive()[i]; + const prevBank = group.getFirstBankByTokenIndex(prevToken.tokenIndex); + accountsToExclude.push(prevBank.publicKey, prevBank.oracle); + } + } const withdrawIx = await this.tokenWithdrawNativeIx( group, mangoAccount, bank.mint, U64_MAX_BN, false, + [...accountsToExclude], ); instructions.push(...withdrawIx); } - for (const serum3Account of mangoAccount.serum3Active()) { - const serum3Market = group.serum3MarketsMapByMarketIndex.get( - serum3Account.marketIndex, - )!.serumMarketExternal!; - const closeOOIx = await this.serum3CloseOpenOrdersIx( - group, - mangoAccount, - serum3Market, - ); - instructions.push(closeOOIx); - } - - for (const perp of mangoAccount.perpActive()) { - const deactivatingPositionIx = await this.perpDeactivatePositionIx( - group, - mangoAccount, - perp.marketIndex, - ); - instructions.push(deactivatingPositionIx); - } - const closeIx = await this.program.methods - .accountClose(forceClose) + .accountClose(false) .accounts({ group: group.publicKey, account: mangoAccount.publicKey, @@ -955,7 +978,7 @@ export class MangoClient { AccountRetriever.Fixed, group, [mangoAccount], - [], + [bank], [], ); @@ -1014,6 +1037,7 @@ export class MangoClient { mintPk: PublicKey, nativeAmount: BN, allowBorrow: boolean, + healthAccountsToExclude: PublicKey[] = [], ): Promise { const bank = group.getFirstBankByMint(mintPk); @@ -1063,10 +1087,21 @@ export class MangoClient { tokenAccount: tokenAccountPk, }) .remainingAccounts( - healthRemainingAccounts.map( - (pk) => - ({ pubkey: pk, isWritable: false, isSigner: false } as AccountMeta), - ), + healthRemainingAccounts + .filter( + (accounts) => + !healthAccountsToExclude.find((accountsToExclude) => + accounts.equals(accountsToExclude), + ), + ) + .map( + (pk) => + ({ + pubkey: pk, + isWritable: false, + isSigner: false, + } as AccountMeta), + ), ) .instruction(); From 572a80d1d0a139c027526579ae82192f4d877e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Brzezin=CC=81ski?= Date: Sun, 15 Jan 2023 01:31:06 +0100 Subject: [PATCH 9/9] review fix --- ts/client/src/client.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index 6535a223b..5139b3616 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -842,16 +842,12 @@ export class MangoClient { serum3Account.marketIndex, )!; - const openOrders = mangoAccount.serum3.find( - (account) => account.marketIndex === serum3Market.marketIndex, - )!.openOrders; - const closeOOIx = await this.serum3CloseOpenOrdersIx( group, mangoAccount, serum3Market.serumMarketExternal, ); - healthAccountsToExclude.push(openOrders); + healthAccountsToExclude.push(serum3Account.openOrders); instructions.push(closeOOIx); }