mc/mango account units docs (#181)

* cleanup mango account docs

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* note

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* Fixes from reviews

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* Fixes from reviews

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* Fixes from reviews

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
microwavedcola1 2022-08-18 16:19:37 +02:00 committed by GitHub
parent 403226dc28
commit 7ad39238b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 107 additions and 30 deletions

View File

@ -99,12 +99,13 @@ export class MangoAccount {
return this.serum3.find((sa) => sa.marketIndex == marketIndex); return this.serum3.find((sa) => sa.marketIndex == marketIndex);
} }
getNative(bank: Bank): I80F48 { // How to navigate
const ta = this.findToken(bank.tokenIndex); // * if a function is returning a I80F48, then usually the return value is in native quote or native token, unless specified
return ta ? ta.native(bank) : ZERO_I80F48; // * if a function is returning a number, then usually the return value is in native tokens, unless specified
} // * functions try to be explicit by having native or ui in the name to better reflect the value
// * some values might appear unexpected large or small, usually the doc contains a "note"
static getEquivalentNativeUsdcPosition( static getEquivalentUsdcPosition(
sourceBank: Bank, sourceBank: Bank,
nativeTokenPosition: TokenPosition, nativeTokenPosition: TokenPosition,
): I80F48 { ): I80F48 {
@ -117,7 +118,7 @@ export class MangoAccount {
: ZERO_I80F48; : ZERO_I80F48;
} }
static getEquivalentNativeTokenPosition( static getEquivalentTokenPosition(
targetBank: Bank, targetBank: Bank,
nativeUsdcPosition: I80F48, nativeUsdcPosition: I80F48,
): I80F48 { ): I80F48 {
@ -127,51 +128,100 @@ export class MangoAccount {
.mul(I80F48.fromNumber(Math.pow(10, targetBank.mintDecimals))); .mul(I80F48.fromNumber(Math.pow(10, targetBank.mintDecimals)));
} }
getNativeDeposits(bank: Bank): I80F48 { /**
const native = this.getNative(bank); *
* @param bank
* @returns native balance for a token
*/
getTokenBalance(bank: Bank): I80F48 {
const ta = this.findToken(bank.tokenIndex);
return ta ? ta.native(bank) : ZERO_I80F48;
}
/**
*
* @param bank
* @returns native balance for a token, 0 or more
*/
getTokenDeposits(bank: Bank): I80F48 {
const native = this.getTokenBalance(bank);
return native.gte(ZERO_I80F48) ? native : ZERO_I80F48; return native.gte(ZERO_I80F48) ? native : ZERO_I80F48;
} }
getNativeBorrows(bank: Bank): I80F48 { /**
const native = this.getNative(bank); *
* @param bank
* @returns native balance for a token, 0 or less
*/
getTokenBorrows(bank: Bank): I80F48 {
const native = this.getTokenBalance(bank);
return native.lte(ZERO_I80F48) ? native : ZERO_I80F48; return native.lte(ZERO_I80F48) ? native : ZERO_I80F48;
} }
getUi(bank: Bank): number { /**
*
* @param bank
* @returns UI balance for a token
*/
getTokenBalanceUi(bank: Bank): number {
const ta = this.findToken(bank.tokenIndex); const ta = this.findToken(bank.tokenIndex);
return ta ? ta.ui(bank) : 0; return ta ? ta.balanceUi(bank) : 0;
} }
deposits(bank: Bank): number { /**
*
* @param bank
* @returns UI balance for a token, 0 or more
*/
getTokenDepositsUi(bank: Bank): number {
const ta = this.findToken(bank.tokenIndex); const ta = this.findToken(bank.tokenIndex);
return ta ? ta.uiDeposits(bank) : 0; return ta ? ta.depositsUi(bank) : 0;
} }
borrows(bank: Bank): number { /**
*
* @param bank
* @returns UI balance for a token, 0 or less
*/
getTokenBorrowsUi(bank: Bank): number {
const ta = this.findToken(bank.tokenIndex); const ta = this.findToken(bank.tokenIndex);
return ta ? ta.uiBorrows(bank) : 0; return ta ? ta.borrowsUi(bank) : 0;
} }
/**
* Health, see health.rs or https://docs.mango.markets/mango-markets/health-overview
* @param healthType
* @returns raw health number, in native quote
*/
getHealth(healthType: HealthType): I80F48 { getHealth(healthType: HealthType): I80F48 {
return healthType == HealthType.init return healthType == HealthType.init
? (this.accountData as MangoAccountData).initHealth ? (this.accountData as MangoAccountData).initHealth
: (this.accountData as MangoAccountData).maintHealth; : (this.accountData as MangoAccountData).maintHealth;
} }
/**
* Health ratio, which is computed so `100 * (assets-liabs)/liabs`
* Note: health ratio is technically if liabs are 0
* @param healthType
* @returns health ratio, in percentage form
*/
getHealthRatio(healthType: HealthType): I80F48 { getHealthRatio(healthType: HealthType): I80F48 {
return this.accountData.healthCache.healthRatio(healthType); return this.accountData.healthCache.healthRatio(healthType);
} }
/**
* Health ratio
* @param healthType
* @returns health ratio, in percentage form, capped to 100
*/
getHealthRatioUi(healthType: HealthType): number { getHealthRatioUi(healthType: HealthType): number {
const ratio = this.accountData.healthCache const ratio = this.getHealthRatio(healthType).toNumber();
.healthRatio(healthType)
.toNumber();
return ratio > 100 ? 100 : Math.trunc(ratio); return ratio > 100 ? 100 : Math.trunc(ratio);
} }
/** /**
* Sum of all the assets i.e. token deposits, borrows, total assets in spot open orders, (perps positions is todo) in terms of quote value. * Sum of all the assets i.e. token deposits, borrows, total assets in spot open orders, (perps positions is todo) in terms of quote value.
* @returns equity, in native quote
*/ */
getEquity(): I80F48 { getEquity(): I80F48 {
const equity = (this.accountData as MangoAccountData).equity; const equity = (this.accountData as MangoAccountData).equity;
@ -184,6 +234,7 @@ export class MangoAccount {
/** /**
* The amount of native quote you could withdraw against your existing assets. * The amount of native quote you could withdraw against your existing assets.
* @returns collateral value, in native quote
*/ */
getCollateralValue(): I80F48 { getCollateralValue(): I80F48 {
return this.getHealth(HealthType.init); return this.getHealth(HealthType.init);
@ -191,15 +242,17 @@ export class MangoAccount {
/** /**
* Sum of all positive assets. * Sum of all positive assets.
* @returns assets, in native quote
*/ */
getAssetsVal(healthType: HealthType): I80F48 { getAssetsValue(healthType: HealthType): I80F48 {
return this.accountData.healthCache.assets(healthType); return this.accountData.healthCache.assets(healthType);
} }
/** /**
* Sum of all negative assets. * Sum of all negative assets.
* @returns liabs, in native quote
*/ */
getLiabsVal(healthType: HealthType): I80F48 { getLiabsValue(healthType: HealthType): I80F48 {
return this.accountData.healthCache.liabs(healthType); return this.accountData.healthCache.liabs(healthType);
} }
@ -207,16 +260,17 @@ export class MangoAccount {
* The amount of given native token you can borrow, considering all existing assets as collateral except the deposits for this token. * 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 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 * 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
*/ */
getMaxWithdrawWithBorrowForToken(group: Group, mintPk: PublicKey): I80F48 { getMaxWithdrawWithBorrowForToken(group: Group, mintPk: PublicKey): I80F48 {
const bank: Bank = group.getFirstBankByMint(mintPk); const bank: Bank = group.getFirstBankByMint(mintPk);
const initHealth = (this.accountData as MangoAccountData).initHealth; const initHealth = (this.accountData as MangoAccountData).initHealth;
const inUsdcUnits = MangoAccount.getEquivalentNativeUsdcPosition( const inUsdcUnits = MangoAccount.getEquivalentUsdcPosition(
bank, bank,
this.findToken(bank.tokenIndex), this.findToken(bank.tokenIndex),
).max(ZERO_I80F48); ).max(ZERO_I80F48);
const newInitHealth = initHealth.sub(inUsdcUnits.mul(bank.initAssetWeight)); const newInitHealth = initHealth.sub(inUsdcUnits.mul(bank.initAssetWeight));
return MangoAccount.getEquivalentNativeTokenPosition( return MangoAccount.getEquivalentTokenPosition(
bank, bank,
newInitHealth.div(bank.initLiabWeight), newInitHealth.div(bank.initLiabWeight),
); );
@ -227,6 +281,7 @@ export class MangoAccount {
* note: slippageAndFeesFactor is a normalized number, <1, * note: slippageAndFeesFactor is a normalized number, <1,
* e.g. a slippage of 5% and some fees which are 1%, then slippageAndFeesFactor = 0.94 * e.g. a slippage of 5% and some fees which are 1%, then slippageAndFeesFactor = 0.94
* the factor is used to compute how much target can be obtained by swapping source * the factor is used to compute how much target can be obtained by swapping source
* @returns max amount of given source native token you can swap to a target token, in native token
*/ */
getMaxSourceForTokenSwap( getMaxSourceForTokenSwap(
group: Group, group: Group,
@ -247,6 +302,8 @@ export class MangoAccount {
/** /**
* Simulates new health ratio after applying tokenChanges to the token positions. * Simulates new health ratio after applying tokenChanges to the token positions.
* e.g. useful to simulate health after a potential swap. * e.g. useful to simulate health after a potential swap.
* Note: health ratio is technically if liabs are 0
* @returns health ratio, in percentage form
*/ */
simHealthRatioWithTokenPositionChanges( simHealthRatioWithTokenPositionChanges(
group: Group, group: Group,
@ -267,7 +324,7 @@ export class MangoAccount {
* The remaining native quote margin available for given market. * The remaining native quote margin available for given market.
* *
* TODO: this is a very bad estimation atm. * TODO: this is a very bad estimation atm.
* It assumes quote asset is always USDC, * It assumes quote asset is always quote,
* it assumes that there are no interaction effects, * it assumes that there are no interaction effects,
* it assumes that there are no existing borrows for either of the tokens in the market. * it assumes that there are no existing borrows for either of the tokens in the market.
*/ */
@ -284,7 +341,7 @@ export class MangoAccount {
* The remaining native quote margin available for given market. * The remaining native quote margin available for given market.
* *
* TODO: this is a very bad estimation atm. * TODO: this is a very bad estimation atm.
* It assumes quote asset is always USDC, * It assumes quote asset is always quote,
* it assumes that there are no interaction effects, * it assumes that there are no interaction effects,
* it assumes that there are no existing borrows for either of the tokens in the market. * it assumes that there are no existing borrows for either of the tokens in the market.
*/ */
@ -370,18 +427,38 @@ export class TokenPosition {
} }
} }
public ui(bank: Bank): number { /**
* @param bank
* @returns position in UI decimals, is signed
*/
public balanceUi(bank: Bank): number {
return nativeI80F48ToUi(this.native(bank), bank.mintDecimals).toNumber(); return nativeI80F48ToUi(this.native(bank), bank.mintDecimals).toNumber();
} }
public uiDeposits(bank: Bank): number { /**
* @param bank
* @returns position in UI decimals, 0 if position has borrows
*/
public depositsUi(bank: Bank): number {
if (this.indexedPosition && this.indexedPosition.lt(ZERO_I80F48)) {
return 0;
}
return nativeI80F48ToUi( return nativeI80F48ToUi(
bank.depositIndex.mul(this.indexedPosition), bank.depositIndex.mul(this.indexedPosition),
bank.mintDecimals, bank.mintDecimals,
).toNumber(); ).toNumber();
} }
public uiBorrows(bank: Bank): number { /**
* @param bank
* @returns position in UI decimals, can be 0 or negative, 0 if position has deposits
*/
public borrowsUi(bank: Bank): number {
if (this.indexedPosition && this.indexedPosition.gt(ZERO_I80F48)) {
return 0;
}
return nativeI80F48ToUi( return nativeI80F48ToUi(
bank.borrowIndex.mul(this.indexedPosition), bank.borrowIndex.mul(this.indexedPosition),
bank.mintDecimals, bank.mintDecimals,
@ -395,7 +472,7 @@ export class TokenPosition {
if (bank) { if (bank) {
const native = this.native(bank); const native = this.native(bank);
extra += ', native: ' + native.toNumber(); extra += ', native: ' + native.toNumber();
extra += ', ui: ' + this.ui(bank); extra += ', ui: ' + this.balanceUi(bank);
extra += ', tokenName: ' + bank.name; extra += ', tokenName: ' + bank.name;
} }
} }