Health from health components in ts/client (#104)
This commit is contained in:
parent
03882e6dd3
commit
bc4c57911a
|
@ -1,11 +1,11 @@
|
||||||
use anchor_lang::prelude::*;
|
use anchor_lang::prelude::*;
|
||||||
use fixed::types::I80F48;
|
use fixed::types::I80F48;
|
||||||
|
|
||||||
use crate::state::{PerpMarketIndex, TokenIndex};
|
use crate::state::{HealthCache, PerpMarketIndex, TokenIndex};
|
||||||
|
|
||||||
#[event]
|
#[event]
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct MangoAccountData {
|
pub struct MangoAccountData {
|
||||||
|
pub health_cache: HealthCache,
|
||||||
pub init_health: I80F48,
|
pub init_health: I80F48,
|
||||||
pub maint_health: I80F48,
|
pub maint_health: I80F48,
|
||||||
pub equity: Equity,
|
pub equity: Equity,
|
||||||
|
|
|
@ -24,9 +24,10 @@ pub fn compute_account_data(ctx: Context<ComputeAccountData>) -> Result<()> {
|
||||||
let equity = compute_equity(&account, &account_retriever)?;
|
let equity = compute_equity(&account, &account_retriever)?;
|
||||||
|
|
||||||
emit!(MangoAccountData {
|
emit!(MangoAccountData {
|
||||||
|
health_cache,
|
||||||
init_health,
|
init_health,
|
||||||
maint_health,
|
maint_health,
|
||||||
equity
|
equity,
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -410,7 +410,8 @@ pub fn compute_health(
|
||||||
Ok(new_health_cache(account, retriever)?.health(health_type))
|
Ok(new_health_cache(account, retriever)?.health(health_type))
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TokenInfo {
|
#[derive(AnchorDeserialize, AnchorSerialize)]
|
||||||
|
pub struct TokenInfo {
|
||||||
token_index: TokenIndex,
|
token_index: TokenIndex,
|
||||||
maint_asset_weight: I80F48,
|
maint_asset_weight: I80F48,
|
||||||
init_asset_weight: I80F48,
|
init_asset_weight: I80F48,
|
||||||
|
@ -451,7 +452,8 @@ impl TokenInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Serum3Info {
|
#[derive(AnchorSerialize, AnchorDeserialize)]
|
||||||
|
pub struct Serum3Info {
|
||||||
reserved: I80F48,
|
reserved: I80F48,
|
||||||
base_index: usize,
|
base_index: usize,
|
||||||
quote_index: usize,
|
quote_index: usize,
|
||||||
|
@ -496,7 +498,8 @@ impl Serum3Info {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PerpInfo {
|
#[derive(AnchorSerialize, AnchorDeserialize)]
|
||||||
|
pub struct PerpInfo {
|
||||||
maint_asset_weight: I80F48,
|
maint_asset_weight: I80F48,
|
||||||
init_asset_weight: I80F48,
|
init_asset_weight: I80F48,
|
||||||
maint_liab_weight: I80F48,
|
maint_liab_weight: I80F48,
|
||||||
|
@ -535,6 +538,7 @@ impl PerpInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(AnchorSerialize, AnchorDeserialize)]
|
||||||
pub struct HealthCache {
|
pub struct HealthCache {
|
||||||
token_infos: Vec<TokenInfo>,
|
token_infos: Vec<TokenInfo>,
|
||||||
serum3_infos: Vec<Serum3Info>,
|
serum3_infos: Vec<Serum3Info>,
|
||||||
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
import { I80F48, I80F48Dto, ZERO_I80F48 } from './I80F48';
|
||||||
|
import { HealthType } from './mangoAccount';
|
||||||
|
|
||||||
|
// ░░░░
|
||||||
|
//
|
||||||
|
// ██
|
||||||
|
// ██░░██
|
||||||
|
// ░░ ░░ ██░░░░░░██ ░░░░
|
||||||
|
// ██░░░░░░░░░░██
|
||||||
|
// ██░░░░░░░░░░██
|
||||||
|
// ██░░░░░░░░░░░░░░██
|
||||||
|
// ██░░░░░░██████░░░░░░██
|
||||||
|
// ██░░░░░░██████░░░░░░██
|
||||||
|
// ██░░░░░░░░██████░░░░░░░░██
|
||||||
|
// ██░░░░░░░░██████░░░░░░░░██
|
||||||
|
// ██░░░░░░░░░░██████░░░░░░░░░░██
|
||||||
|
// ██░░░░░░░░░░░░██████░░░░░░░░░░░░██
|
||||||
|
// ██░░░░░░░░░░░░██████░░░░░░░░░░░░██
|
||||||
|
// ██░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░██
|
||||||
|
// ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██
|
||||||
|
// ██░░░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░░░██
|
||||||
|
// ██░░░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░░░██
|
||||||
|
// ██░░░░░░░░░░░░░░░░░░██████░░░░░░░░░░░░░░░░░░██
|
||||||
|
// ░░ ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██
|
||||||
|
// ██████████████████████████████████████████
|
||||||
|
// warning: this code is copy pasta from rust, keep in sync with health.rs
|
||||||
|
|
||||||
|
export class HealthCache {
|
||||||
|
tokenInfos: TokenInfo[];
|
||||||
|
serum3Infos: Serum3Info[];
|
||||||
|
perpInfos: PerpInfo[];
|
||||||
|
|
||||||
|
constructor(dto: HealthCacheDto) {
|
||||||
|
this.tokenInfos = dto.tokenInfos.map((dto) => new TokenInfo(dto));
|
||||||
|
this.serum3Infos = dto.serum3Infos.map((dto) => new Serum3Info(dto));
|
||||||
|
this.perpInfos = dto.perpInfos.map((dto) => new PerpInfo(dto));
|
||||||
|
}
|
||||||
|
|
||||||
|
public health(healthType: HealthType): I80F48 {
|
||||||
|
let health = ZERO_I80F48;
|
||||||
|
for (const tokenInfo of this.tokenInfos) {
|
||||||
|
let contrib = tokenInfo.healthContribution(healthType);
|
||||||
|
health = health.add(contrib);
|
||||||
|
}
|
||||||
|
for (const serum3Info of this.serum3Infos) {
|
||||||
|
let contrib = serum3Info.healthContribution(healthType, this.tokenInfos);
|
||||||
|
health = health.add(contrib);
|
||||||
|
}
|
||||||
|
for (const perpInfo of this.perpInfos) {
|
||||||
|
let contrib = perpInfo.healthContribution(healthType);
|
||||||
|
health = health.add(contrib);
|
||||||
|
}
|
||||||
|
return health;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TokenInfo {
|
||||||
|
constructor(dto: TokenInfoDto) {
|
||||||
|
this.tokenIndex = dto.tokenIndex;
|
||||||
|
this.maintAssetWeight = I80F48.from(dto.maintAssetWeight);
|
||||||
|
this.initAssetWeight = I80F48.from(dto.initAssetWeight);
|
||||||
|
this.maintLiabWeight = I80F48.from(dto.maintLiabWeight);
|
||||||
|
this.initLiabWeight = I80F48.from(dto.initLiabWeight);
|
||||||
|
this.oraclePrice = I80F48.from(dto.oraclePrice);
|
||||||
|
this.balance = I80F48.from(dto.balance);
|
||||||
|
this.serum3MaxReserved = I80F48.from(dto.serum3MaxReserved);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenIndex: number;
|
||||||
|
maintAssetWeight: I80F48;
|
||||||
|
initAssetWeight: I80F48;
|
||||||
|
maintLiabWeight: I80F48;
|
||||||
|
initLiabWeight: I80F48;
|
||||||
|
oraclePrice: I80F48; // native/native
|
||||||
|
// in health-reference-token native units
|
||||||
|
balance: I80F48;
|
||||||
|
// in health-reference-token native units
|
||||||
|
serum3MaxReserved: I80F48;
|
||||||
|
|
||||||
|
assetWeight(healthType: HealthType): I80F48 {
|
||||||
|
return healthType == HealthType.init
|
||||||
|
? this.initAssetWeight
|
||||||
|
: this.maintAssetWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
liabWeight(healthType: HealthType): I80F48 {
|
||||||
|
return healthType == HealthType.init
|
||||||
|
? this.initLiabWeight
|
||||||
|
: this.maintLiabWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
healthContribution(healthType: HealthType): I80F48 {
|
||||||
|
return (
|
||||||
|
this.balance.isNeg()
|
||||||
|
? this.liabWeight(healthType)
|
||||||
|
: this.assetWeight(healthType)
|
||||||
|
).mul(this.balance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Serum3Info {
|
||||||
|
constructor(dto: Serum3InfoDto) {
|
||||||
|
this.reserved = I80F48.from(dto.reserved);
|
||||||
|
this.baseIndex = dto.baseIndex;
|
||||||
|
this.quoteIndex = dto.quoteIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
reserved: I80F48;
|
||||||
|
baseIndex: number;
|
||||||
|
quoteIndex: number;
|
||||||
|
|
||||||
|
healthContribution(healthType: HealthType, tokenInfos: TokenInfo[]): I80F48 {
|
||||||
|
let baseInfo = tokenInfos[this.baseIndex];
|
||||||
|
let quoteInfo = tokenInfos[this.quoteIndex];
|
||||||
|
let reserved = this.reserved;
|
||||||
|
|
||||||
|
if (reserved.isZero()) {
|
||||||
|
return ZERO_I80F48;
|
||||||
|
}
|
||||||
|
|
||||||
|
// How much the health would increase if the reserved balance were applied to the passed
|
||||||
|
// token info?
|
||||||
|
let computeHealthEffect = function (tokenInfo: TokenInfo) {
|
||||||
|
// This balance includes all possible reserved funds from markets that relate to the
|
||||||
|
// token, including this market itself: `reserved` is already included in `max_balance`.
|
||||||
|
let maxBalance = tokenInfo.balance.add(tokenInfo.serum3MaxReserved);
|
||||||
|
|
||||||
|
// Assuming `reserved` was added to `max_balance` last (because that gives the smallest
|
||||||
|
// health effects): how much did health change because of it?
|
||||||
|
let assetPart, liabPart;
|
||||||
|
if (maxBalance.gte(reserved)) {
|
||||||
|
assetPart = reserved;
|
||||||
|
liabPart = ZERO_I80F48;
|
||||||
|
} else if (maxBalance.isNeg()) {
|
||||||
|
assetPart = ZERO_I80F48;
|
||||||
|
liabPart = reserved;
|
||||||
|
} else {
|
||||||
|
assetPart = maxBalance;
|
||||||
|
liabPart = reserved.sub(maxBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
let assetWeight = tokenInfo.assetWeight(healthType);
|
||||||
|
let liabWeight = tokenInfo.liabWeight(healthType);
|
||||||
|
return assetWeight.mul(assetPart).add(liabWeight.mul(liabPart));
|
||||||
|
};
|
||||||
|
|
||||||
|
let reservedAsBase = computeHealthEffect(baseInfo);
|
||||||
|
let reservedAsQuote = computeHealthEffect(quoteInfo);
|
||||||
|
return reservedAsBase.min(reservedAsQuote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PerpInfo {
|
||||||
|
constructor(dto: PerpInfoDto) {
|
||||||
|
this.maintAssetWeight = I80F48.from(dto.maintAssetWeight);
|
||||||
|
this.initAssetWeight = I80F48.from(dto.initAssetWeight);
|
||||||
|
this.maintLiabWeight = I80F48.from(dto.maintLiabWeight);
|
||||||
|
this.initLiabWeight = I80F48.from(dto.initLiabWeight);
|
||||||
|
this.base = I80F48.from(dto.base);
|
||||||
|
this.quote = I80F48.from(dto.quote);
|
||||||
|
}
|
||||||
|
maintAssetWeight: I80F48;
|
||||||
|
initAssetWeight: I80F48;
|
||||||
|
maintLiabWeight: I80F48;
|
||||||
|
initLiabWeight: I80F48;
|
||||||
|
// in health-reference-token native units, needs scaling by asset/liab
|
||||||
|
base: I80F48;
|
||||||
|
// in health-reference-token native units, no asset/liab factor needed
|
||||||
|
quote: I80F48;
|
||||||
|
|
||||||
|
healthContribution(healthType: HealthType): I80F48 {
|
||||||
|
let weight;
|
||||||
|
if (healthType == HealthType.init && this.base.isNeg()) {
|
||||||
|
weight = this.initLiabWeight;
|
||||||
|
} else if (healthType == HealthType.init && !this.base.isNeg()) {
|
||||||
|
weight = this.initAssetWeight;
|
||||||
|
}
|
||||||
|
if (healthType == HealthType.maint && this.base.isNeg()) {
|
||||||
|
weight = this.maintLiabWeight;
|
||||||
|
}
|
||||||
|
if (healthType == HealthType.maint && !this.base.isNeg()) {
|
||||||
|
weight = this.maintAssetWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUTURE: Allow v3-style "reliable" markets where we can return
|
||||||
|
// `self.quote + weight * self.base` here
|
||||||
|
return this.quote.add(weight.mul(this.base)).min(ZERO_I80F48);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HealthCacheDto {
|
||||||
|
tokenInfos: TokenInfoDto[];
|
||||||
|
serum3Infos: Serum3InfoDto[];
|
||||||
|
perpInfos: PerpInfoDto[];
|
||||||
|
}
|
||||||
|
export class TokenInfoDto {
|
||||||
|
tokenIndex: number;
|
||||||
|
maintAssetWeight: I80F48Dto;
|
||||||
|
initAssetWeight: I80F48Dto;
|
||||||
|
maintLiabWeight: I80F48Dto;
|
||||||
|
initLiabWeight: I80F48Dto;
|
||||||
|
oraclePrice: I80F48Dto; // native/native
|
||||||
|
// in health-reference-token native units
|
||||||
|
balance: I80F48Dto;
|
||||||
|
// in health-reference-token native units
|
||||||
|
serum3MaxReserved: I80F48Dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Serum3InfoDto {
|
||||||
|
reserved: I80F48Dto;
|
||||||
|
baseIndex: number;
|
||||||
|
quoteIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PerpInfoDto {
|
||||||
|
maintAssetWeight: I80F48Dto;
|
||||||
|
initAssetWeight: I80F48Dto;
|
||||||
|
maintLiabWeight: I80F48Dto;
|
||||||
|
initLiabWeight: I80F48Dto;
|
||||||
|
// in health-reference-token native units, needs scaling by asset/liab
|
||||||
|
base: I80F48Dto;
|
||||||
|
// in health-reference-token native units, no asset/liab factor needed
|
||||||
|
quote: I80F48Dto;
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import { MangoClient } from '../client';
|
||||||
import { nativeI80F48ToUi } from '../utils';
|
import { nativeI80F48ToUi } from '../utils';
|
||||||
import { Bank, QUOTE_DECIMALS } from './bank';
|
import { Bank, QUOTE_DECIMALS } from './bank';
|
||||||
import { Group } from './group';
|
import { Group } from './group';
|
||||||
|
import { HealthCache, HealthCacheDto } from './healthCache';
|
||||||
import { I80F48, I80F48Dto, ONE_I80F48, ZERO_I80F48 } from './I80F48';
|
import { I80F48, I80F48Dto, ONE_I80F48, ZERO_I80F48 } from './I80F48';
|
||||||
export class MangoAccount {
|
export class MangoAccount {
|
||||||
public tokens: TokenPosition[];
|
public tokens: TokenPosition[];
|
||||||
|
@ -422,12 +423,14 @@ export class HealthType {
|
||||||
|
|
||||||
export class MangoAccountData {
|
export class MangoAccountData {
|
||||||
constructor(
|
constructor(
|
||||||
|
public healthCache: HealthCache,
|
||||||
public initHealth: I80F48,
|
public initHealth: I80F48,
|
||||||
public maintHealth: I80F48,
|
public maintHealth: I80F48,
|
||||||
public equity: Equity,
|
public equity: Equity,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
static from(event: {
|
static from(event: {
|
||||||
|
healthCache: HealthCacheDto;
|
||||||
initHealth: I80F48Dto;
|
initHealth: I80F48Dto;
|
||||||
maintHealth: I80F48Dto;
|
maintHealth: I80F48Dto;
|
||||||
equity: {
|
equity: {
|
||||||
|
@ -438,6 +441,7 @@ export class MangoAccountData {
|
||||||
tokenAssets: any;
|
tokenAssets: any;
|
||||||
}) {
|
}) {
|
||||||
return new MangoAccountData(
|
return new MangoAccountData(
|
||||||
|
new HealthCache(event.healthCache),
|
||||||
I80F48.from(event.initHealth),
|
I80F48.from(event.initHealth),
|
||||||
I80F48.from(event.maintHealth),
|
I80F48.from(event.maintHealth),
|
||||||
Equity.from(event.equity),
|
Equity.from(event.equity),
|
||||||
|
|
|
@ -3427,6 +3427,158 @@ export type MangoV4 = {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "TokenInfo",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "tokenIndex",
|
||||||
|
"type": "u16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintLiabWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initLiabWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "oraclePrice",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "balance",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "serum3MaxReserved",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Serum3Info",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "reserved",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "baseIndex",
|
||||||
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quoteIndex",
|
||||||
|
"type": "u64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PerpInfo",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "maintAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintLiabWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initLiabWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "base",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quote",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HealthCache",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "tokenInfos",
|
||||||
|
"type": {
|
||||||
|
"vec": {
|
||||||
|
"defined": "TokenInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "serum3Infos",
|
||||||
|
"type": {
|
||||||
|
"vec": {
|
||||||
|
"defined": "Serum3Info"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "perpInfos",
|
||||||
|
"type": {
|
||||||
|
"vec": {
|
||||||
|
"defined": "PerpInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "TokenPosition",
|
"name": "TokenPosition",
|
||||||
"type": {
|
"type": {
|
||||||
|
@ -4046,6 +4198,13 @@ export type MangoV4 = {
|
||||||
{
|
{
|
||||||
"name": "MangoAccountData",
|
"name": "MangoAccountData",
|
||||||
"fields": [
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "healthCache",
|
||||||
|
"type": {
|
||||||
|
"defined": "HealthCache"
|
||||||
|
},
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "initHealth",
|
"name": "initHealth",
|
||||||
"type": {
|
"type": {
|
||||||
|
@ -8048,6 +8207,158 @@ export const IDL: MangoV4 = {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "TokenInfo",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "tokenIndex",
|
||||||
|
"type": "u16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintLiabWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initLiabWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "oraclePrice",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "balance",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "serum3MaxReserved",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Serum3Info",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "reserved",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "baseIndex",
|
||||||
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quoteIndex",
|
||||||
|
"type": "u64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PerpInfo",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "maintAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initAssetWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maintLiabWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initLiabWeight",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "base",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quote",
|
||||||
|
"type": {
|
||||||
|
"defined": "I80F48"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HealthCache",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "tokenInfos",
|
||||||
|
"type": {
|
||||||
|
"vec": {
|
||||||
|
"defined": "TokenInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "serum3Infos",
|
||||||
|
"type": {
|
||||||
|
"vec": {
|
||||||
|
"defined": "Serum3Info"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "perpInfos",
|
||||||
|
"type": {
|
||||||
|
"vec": {
|
||||||
|
"defined": "PerpInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "TokenPosition",
|
"name": "TokenPosition",
|
||||||
"type": {
|
"type": {
|
||||||
|
@ -8667,6 +8978,13 @@ export const IDL: MangoV4 = {
|
||||||
{
|
{
|
||||||
"name": "MangoAccountData",
|
"name": "MangoAccountData",
|
||||||
"fields": [
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "healthCache",
|
||||||
|
"type": {
|
||||||
|
"defined": "HealthCache"
|
||||||
|
},
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "initHealth",
|
"name": "initHealth",
|
||||||
"type": {
|
"type": {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { AnchorProvider, Wallet } from '@project-serum/anchor';
|
import { AnchorProvider, Wallet } from '@project-serum/anchor';
|
||||||
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
import { HealthType } from '../accounts/mangoAccount';
|
||||||
import { OrderType, Side } from '../accounts/perp';
|
import { OrderType, Side } from '../accounts/perp';
|
||||||
import {
|
import {
|
||||||
Serum3OrderType,
|
Serum3OrderType,
|
||||||
|
@ -67,12 +68,22 @@ async function main() {
|
||||||
const randomKey = new PublicKey(
|
const randomKey = new PublicKey(
|
||||||
'4ZkS7ZZkxfsC3GtvvsHP3DFcUeByU9zzZELS4r8HCELo',
|
'4ZkS7ZZkxfsC3GtvvsHP3DFcUeByU9zzZELS4r8HCELo',
|
||||||
);
|
);
|
||||||
await client.editMangoAccount(group, mangoAccount, 'my_changed_name', randomKey);
|
await client.editMangoAccount(
|
||||||
|
group,
|
||||||
|
mangoAccount,
|
||||||
|
'my_changed_name',
|
||||||
|
randomKey,
|
||||||
|
);
|
||||||
await mangoAccount.reload(client, group);
|
await mangoAccount.reload(client, group);
|
||||||
console.log(mangoAccount.toString());
|
console.log(mangoAccount.toString());
|
||||||
|
|
||||||
console.log(`...resetting mango account name, and re-setting a delegate`);
|
console.log(`...resetting mango account name, and re-setting a delegate`);
|
||||||
await client.editMangoAccount(group, mangoAccount, 'my_mango_account', PublicKey.default);
|
await client.editMangoAccount(
|
||||||
|
group,
|
||||||
|
mangoAccount,
|
||||||
|
'my_mango_account',
|
||||||
|
PublicKey.default,
|
||||||
|
);
|
||||||
await mangoAccount.reload(client, group);
|
await mangoAccount.reload(client, group);
|
||||||
console.log(mangoAccount.toString());
|
console.log(mangoAccount.toString());
|
||||||
}
|
}
|
||||||
|
@ -199,6 +210,14 @@ async function main() {
|
||||||
'...mangoAccount.getCollateralValue() ' +
|
'...mangoAccount.getCollateralValue() ' +
|
||||||
toUiDecimals(mangoAccount.getCollateralValue().toNumber()),
|
toUiDecimals(mangoAccount.getCollateralValue().toNumber()),
|
||||||
);
|
);
|
||||||
|
console.log(
|
||||||
|
'...mangoAccount.accountData["healthCache"].health(HealthType.init) ' +
|
||||||
|
toUiDecimals(
|
||||||
|
mangoAccount.accountData['healthCache']
|
||||||
|
.health(HealthType.init)
|
||||||
|
.toNumber(),
|
||||||
|
),
|
||||||
|
);
|
||||||
console.log(
|
console.log(
|
||||||
'...mangoAccount.getAssetsVal() ' +
|
'...mangoAccount.getAssetsVal() ' +
|
||||||
toUiDecimals(mangoAccount.getAssetsVal().toNumber()),
|
toUiDecimals(mangoAccount.getAssetsVal().toNumber()),
|
||||||
|
|
Loading…
Reference in New Issue