diff --git a/ts/client/src/accounts/group.ts b/ts/client/src/accounts/group.ts index 86d2b8a0b..5f78e0484 100644 --- a/ts/client/src/accounts/group.ts +++ b/ts/client/src/accounts/group.ts @@ -1,16 +1,17 @@ import { BorshAccountsCoder } from '@project-serum/anchor'; +import { coder } from '@project-serum/anchor/dist/cjs/spl/associated-token'; import { Market } from '@project-serum/serum'; import { parsePriceData, PriceData } from '@pythnetwork/client'; import { PublicKey } from '@solana/web3.js'; +import BN from 'bn.js'; import { MangoClient } from '../client'; import { SERUM3_PROGRAM_ID } from '../constants'; import { Id } from '../ids'; +import { toNativeDecimals } from '../utils'; import { Bank, MintInfo } from './bank'; import { I80F48, ONE_I80F48 } from './I80F48'; import { PerpMarket } from './perp'; import { Serum3Market } from './serum3'; -import { toNativeDecimals } from '../utils'; -import BN from 'bn.js'; export class Group { static from( @@ -267,6 +268,30 @@ export class Group { return this.banksMapByTokenIndex.get(tokenIndex)[0]; } + /** + * + * @param client + * @param mintPk + * @returns sum of native balances of all vaults for a token + */ + public async getGroupTokenVaultBalanceByMint( + client: MangoClient, + mintPk: PublicKey, + ): Promise { + const banks = this.banksMapByMint.get(mintPk.toString()); + const amount = new BN(0); + for (const bank of banks) { + amount.add( + coder().accounts.decode( + 'token', + (await client.program.provider.connection.getAccountInfo(bank.vault)) + .data, + ).amount, + ); + } + return new I80F48(amount); + } + public consoleLogBanks() { for (const mintBanks of this.banksMapByMint.values()) { for (const bank of mintBanks) { diff --git a/ts/client/src/accounts/healthCache.ts b/ts/client/src/accounts/healthCache.ts index 6efbe6fbd..d087168a9 100644 --- a/ts/client/src/accounts/healthCache.ts +++ b/ts/client/src/accounts/healthCache.ts @@ -365,8 +365,8 @@ export class HealthCache { return amount .div(source.oraclePrice) - .mul( - ONE_I80F48.sub( + .div( + ONE_I80F48.add( group.getFirstBankByMint(sourceMintPk).loanOriginationFeeRate, ), ); diff --git a/ts/client/src/accounts/mangoAccount.ts b/ts/client/src/accounts/mangoAccount.ts index 3918bdcdf..83984c236 100644 --- a/ts/client/src/accounts/mangoAccount.ts +++ b/ts/client/src/accounts/mangoAccount.ts @@ -101,11 +101,9 @@ export class MangoAccount { static getEquivalentUsdcPosition( sourceBank: Bank, - nativeTokenPosition: TokenPosition, + tp: TokenPosition, ): I80F48 { - return nativeTokenPosition - ? nativeTokenPosition.balance(sourceBank).mul(sourceBank.price) - : ZERO_I80F48; + return tp ? tp.balance(sourceBank).mul(sourceBank.price) : ZERO_I80F48; } static getEquivalentTokenPosition( @@ -244,23 +242,27 @@ export class MangoAccount { } /** - * The amount of given native token you can borrow, considering all existing assets as collateral except the deposits for this token. - * Note 1: The existing native deposits need to be added to get the full amount that could be withdrawn. - * Note 2: The group might have less native deposits than what this returns. TODO: loan origination fees - * @returns amount of given native token you can borrow, considering all existing assets as collateral except the deposits for this token, in native token + * The amount of given native token you can withdraw including borrows, considering all existing assets as collateral. + * @returns amount of given native token you can borrow, considering all existing assets as collateral, in native token */ getMaxWithdrawWithBorrowForToken(group: Group, mintPk: PublicKey): I80F48 { const bank: Bank = group.getFirstBankByMint(mintPk); const initHealth = (this.accountData as MangoAccountData).initHealth; - const inUsdcUnits = MangoAccount.getEquivalentUsdcPosition( + const existingPositioninUsdcUnits = MangoAccount.getEquivalentUsdcPosition( bank, this.findToken(bank.tokenIndex), ).max(ZERO_I80F48); - const newInitHealth = initHealth.sub(inUsdcUnits.mul(bank.initAssetWeight)); - return MangoAccount.getEquivalentTokenPosition( - bank, - newInitHealth.div(bank.initLiabWeight), + const initHealthWithoutExistingPosition = initHealth.sub( + existingPositioninUsdcUnits.mul(bank.initAssetWeight), ); + const maxBorrowNative = MangoAccount.getEquivalentTokenPosition( + bank, + initHealthWithoutExistingPosition.div(bank.initLiabWeight), + ); + const maxBorrowNativeWithoutFees = maxBorrowNative.div( + ONE_I80F48.add(bank.loanOriginationFeeRate), + ); + return maxBorrowNativeWithoutFees.add(this.getTokenBalance(bank)); } /** diff --git a/ts/client/src/debug-scripts/mb-debug-banks.ts b/ts/client/src/debug-scripts/mb-debug-banks.ts index 6357aac06..b53c205a8 100644 --- a/ts/client/src/debug-scripts/mb-debug-banks.ts +++ b/ts/client/src/debug-scripts/mb-debug-banks.ts @@ -73,9 +73,8 @@ async function main() { coder() .accounts.decode( 'token', - await ( - await client.program.provider.connection.getAccountInfo(bank.vault) - ).data, + (await client.program.provider.connection.getAccountInfo(bank.vault)) + .data, ) .amount.toNumber(), );