diff --git a/ts/client/src/client.ts b/ts/client/src/client.ts index 0aea6ca7d..b5ed63389 100644 --- a/ts/client/src/client.ts +++ b/ts/client/src/client.ts @@ -22,11 +22,7 @@ import { import bs58 from 'bs58'; import { Bank, MintInfo, TokenIndex } from './accounts/bank'; import { Group } from './accounts/group'; -import { - MangoAccount, - PerpPosition, - TokenPosition, -} from './accounts/mangoAccount'; +import { MangoAccount } from './accounts/mangoAccount'; import { StubOracle } from './accounts/oracle'; import { FillEvent, @@ -48,12 +44,7 @@ import { OPENBOOK_PROGRAM_ID } from './constants'; import { Id } from './ids'; import { IDL, MangoV4 } from './mango_v4'; import { I80F48 } from './numbers/I80F48'; -import { - AdditionalHealthAccounts, - FlashLoanType, - InterestRateParams, - OracleConfigParams, -} from './types'; +import { FlashLoanType, InterestRateParams, OracleConfigParams } from './types'; import { I64_MAX_BN, createAssociatedTokenAccountIdempotentInstruction, @@ -1198,44 +1189,30 @@ export class MangoClient { externalMarketPk.toBase58(), )!; - let ooPk; - let healthAdditionalAccounts: AdditionalHealthAccounts | undefined = - undefined; - const healthBanks: Bank[] = []; + let openOrderPk: PublicKey | undefined = undefined; + const banks: Bank[] = []; + const openOrdersForMarket: [Serum3Market, PublicKey][] = []; if (!mangoAccount.getSerum3Account(serum3Market.marketIndex)) { const ix = await this.serum3CreateOpenOrdersIx( group, mangoAccount, serum3Market.serumMarketExternal, ); - - ooPk = await serum3Market.findOoPda( + ixs.push(ix); + openOrderPk = await serum3Market.findOoPda( this.program.programId, mangoAccount.publicKey, ); + openOrdersForMarket.push([serum3Market, openOrderPk]); const baseTokenIndex = serum3Market.baseTokenIndex; const quoteTokenIndex = serum3Market.quoteTokenIndex; - const baseBank = group.getFirstBankByTokenIndex(baseTokenIndex); - const quoteBank = group.getFirstBankByTokenIndex(quoteTokenIndex); - - // only push bank/oracle if no deposit has been previously made for same token - const baseTokenIsInactive = !mangoAccount - .getToken(baseTokenIndex) - ?.isActive(); - const quoteTokenIsInactive = !mangoAccount - .getToken(quoteTokenIndex) - ?.isActive(); - - if (baseTokenIsInactive) { - healthBanks.push(baseBank); + // only include banks if no deposit has been previously made for same token + if (!mangoAccount.getToken(baseTokenIndex)?.isActive()) { + banks.push(group.getFirstBankByTokenIndex(baseTokenIndex)); } - if (quoteTokenIsInactive) { - healthBanks.push(quoteBank); + if (!mangoAccount.getToken(quoteTokenIndex)?.isActive()) { + banks.push(group.getFirstBankByTokenIndex(quoteTokenIndex)); } - healthAdditionalAccounts = { - openOrders: [ooPk], - }; - ixs.push(ix); } const healthRemainingAccounts: PublicKey[] = @@ -1243,9 +1220,9 @@ export class MangoClient { AccountRetriever.Fixed, group, [mangoAccount], - healthBanks, + banks, [], - healthAdditionalAccounts, + openOrdersForMarket, ); const serum3MarketExternal = group.serum3ExternalMarketsMap.get( @@ -1293,7 +1270,7 @@ export class MangoClient { account: mangoAccount.publicKey, owner: (this.program.provider as AnchorProvider).wallet.publicKey, openOrders: - ooPk || + openOrderPk || mangoAccount.getSerum3Account(serum3Market.marketIndex)?.openOrders, serumMarket: serum3Market.publicKey, serumProgram: OPENBOOK_PROGRAM_ID[this.cluster], @@ -2578,9 +2555,9 @@ export class MangoClient { retriever: AccountRetriever, group: Group, mangoAccounts: MangoAccount[], - banks: Bank[], - perpMarkets: PerpMarket[], - additionalAccounts?: AdditionalHealthAccounts, + banks: Bank[] = [], + perpMarkets: PerpMarket[] = [], + openOrdersForMarket: [Serum3Market, PublicKey][] = [], ): PublicKey[] { if (retriever === AccountRetriever.Fixed) { return this.buildFixedAccountRetrieverHealthAccounts( @@ -2588,7 +2565,7 @@ export class MangoClient { mangoAccounts[0], banks, perpMarkets, - additionalAccounts, + openOrdersForMarket, ); } else { return this.buildScanningAccountRetrieverHealthAccounts( @@ -2607,33 +2584,26 @@ export class MangoClient { // but user would potentially open new positions. banks: Bank[], perpMarkets: PerpMarket[], - additionalAccounts: AdditionalHealthAccounts = { - openOrders: [], - }, + openOrdersForMarket: [Serum3Market, PublicKey][], ): PublicKey[] { const healthRemainingAccounts: PublicKey[] = []; - const allTokenIndices = mangoAccount.tokens.map( - (token) => token.tokenIndex, - ); - - if (banks) { - for (const bank of banks) { - if (allTokenIndices.indexOf(bank.tokenIndex) < 0) { - allTokenIndices[ - mangoAccount.tokens.findIndex( - (token, index) => - !token.isActive() && - allTokenIndices[index] == TokenPosition.TokenIndexUnset, - ) - ] = bank.tokenIndex; + const tokenPositions = [...mangoAccount.tokens]; + for (const bank of banks) { + const tokenPositionExists = tokenPositions.find( + (t) => t.tokenIndex === bank.tokenIndex, + ); + if (!tokenPositionExists) { + const inActiveTokenPosition = tokenPositions.find((t) => !t.isActive()); + if (inActiveTokenPosition) { + inActiveTokenPosition.tokenIndex = bank.tokenIndex; } } } - const mintInfos = allTokenIndices - .filter((index) => index != TokenPosition.TokenIndexUnset) - .map((tokenIndex) => group.mintInfosMapByTokenIndex.get(tokenIndex)!); + const mintInfos = tokenPositions + .filter((token) => token.isActive()) + .map((token) => group.mintInfosMapByTokenIndex.get(token.tokenIndex)!); healthRemainingAccounts.push( ...mintInfos.map((mintInfo) => mintInfo.firstBank()), ); @@ -2641,35 +2611,49 @@ export class MangoClient { ...mintInfos.map((mintInfo) => mintInfo.oracle), ); - const allPerpIndices = mangoAccount.perps.map((perp) => perp.marketIndex); - // insert any extra perp markets in the free perp position slots - if (perpMarkets) { - for (const perpMarket of perpMarkets) { - if (allPerpIndices.indexOf(perpMarket.perpMarketIndex) < 0) { - allPerpIndices[ - mangoAccount.perps.findIndex( - (perp, index) => - !perp.isActive() && - allPerpIndices[index] == PerpPosition.PerpMarketIndexUnset, - ) - ] = perpMarket.perpMarketIndex; + const perpPositions = [...mangoAccount.perps]; + for (const perpMarket of perpMarkets) { + const perpPositionExists = perpPositions.find( + (p) => p.marketIndex === perpMarket.perpMarketIndex, + ); + if (!perpPositionExists) { + const perpPosition = perpPositions.find((perp) => !perp.isActive()); + if (perpPosition) { + perpPosition.marketIndex = perpMarket.perpMarketIndex; } } } - const allPerpMarkets = allPerpIndices - .filter((index) => index != PerpPosition.PerpMarketIndexUnset) - .map((index) => group.findPerpMarket(index)!); + + const allPerpMarkets = perpPositions + .filter((perp) => perp.isActive()) + .map((perp) => group.getPerpMarketByMarketIndex(perp.marketIndex)!); healthRemainingAccounts.push( ...allPerpMarkets.map((perp) => perp.publicKey), ); healthRemainingAccounts.push(...allPerpMarkets.map((perp) => perp.oracle)); + // insert any extra open orders accounts in the cooresponding free serum market slot + const serumOpenOrders = [...mangoAccount.serum3]; + for (const [serum3Market, openOrderPk] of openOrdersForMarket) { + const ooPositionExists = serumOpenOrders.find( + (oo) => oo.marketIndex === serum3Market.marketIndex, + ); + if (!ooPositionExists) { + const serum3Order = serumOpenOrders.find( + (serumOrder) => !serumOrder.isActive(), + ); + if (serum3Order) { + serum3Order.marketIndex = serum3Market.marketIndex; + serum3Order.openOrders = openOrderPk; + } + } + } + healthRemainingAccounts.push( - ...mangoAccount.serum3 - .filter((serum3Account) => serum3Account.marketIndex !== 65535) + ...serumOpenOrders + .filter((serum3Account) => serum3Account.isActive()) .map((serum3Account) => serum3Account.openOrders), - ...additionalAccounts.openOrders, ); // debugHealthAccounts(group, mangoAccount, healthRemainingAccounts); diff --git a/ts/client/src/types.ts b/ts/client/src/types.ts index 507d653aa..88c1f47d3 100644 --- a/ts/client/src/types.ts +++ b/ts/client/src/types.ts @@ -26,7 +26,3 @@ export class OracleConfigParams { confFilter: number; maxStalenessSlots: number | null; } - -export type AdditionalHealthAccounts = { - openOrders: PublicKey[]; -};