mango-v4/ts/client/src/accounts/bank.ts

305 lines
8.1 KiB
TypeScript

import { BN } from '@project-serum/anchor';
import { utf8 } from '@project-serum/anchor/dist/cjs/utils/bytes';
import { PublicKey } from '@solana/web3.js';
import { nativeI80F48ToUi } from '../utils';
import { I80F48, I80F48Dto, ZERO_I80F48 } from './I80F48';
export const QUOTE_DECIMALS = 6;
type OracleConfig = {
confFilter: I80F48Dto;
};
export class Bank {
public name: string;
public depositIndex: I80F48;
public borrowIndex: I80F48;
public cachedIndexedTotalDeposits: I80F48;
public cachedIndexedTotalBorrows: I80F48;
public maxRate: I80F48;
public rate0: I80F48;
public rate1: I80F48;
public util0: I80F48;
public util1: I80F48;
public price: I80F48;
public initAssetWeight: I80F48;
public maintAssetWeight: I80F48;
public initLiabWeight: I80F48;
public maintLiabWeight: I80F48;
public liquidationFee: I80F48;
static from(
publicKey: PublicKey,
obj: {
name: number[];
group: PublicKey;
mint: PublicKey;
vault: PublicKey;
oracle: PublicKey;
oracleConfig: OracleConfig;
depositIndex: I80F48Dto;
borrowIndex: I80F48Dto;
cachedIndexedTotalDeposits: I80F48Dto;
cachedIndexedTotalBorrows: I80F48Dto;
lastUpdated: BN;
util0: I80F48Dto;
rate0: I80F48Dto;
util1: I80F48Dto;
rate1: I80F48Dto;
maxRate: I80F48Dto;
collectedFeesNative: I80F48Dto;
loanOriginationFeeRate: I80F48Dto;
loanFeeRate: I80F48Dto;
maintAssetWeight: I80F48Dto;
initAssetWeight: I80F48Dto;
maintLiabWeight: I80F48Dto;
initLiabWeight: I80F48Dto;
liquidationFee: I80F48Dto;
dust: Object;
tokenIndex: number;
mintDecimals: number;
},
) {
return new Bank(
publicKey,
obj.name,
obj.group,
obj.mint,
obj.vault,
obj.oracle,
obj.oracleConfig,
obj.depositIndex,
obj.borrowIndex,
obj.cachedIndexedTotalDeposits,
obj.cachedIndexedTotalBorrows,
obj.lastUpdated,
obj.util0,
obj.rate0,
obj.util1,
obj.rate1,
obj.maxRate,
obj.collectedFeesNative,
obj.loanOriginationFeeRate,
obj.loanFeeRate,
obj.maintAssetWeight,
obj.initAssetWeight,
obj.maintLiabWeight,
obj.initLiabWeight,
obj.liquidationFee,
obj.dust,
obj.tokenIndex,
obj.mintDecimals,
);
}
constructor(
public publicKey: PublicKey,
name: number[],
public group: PublicKey,
public mint: PublicKey,
public vault: PublicKey,
public oracle: PublicKey,
oracleConfig: OracleConfig,
depositIndex: I80F48Dto,
borrowIndex: I80F48Dto,
indexedTotalDeposits: I80F48Dto,
indexedTotalBorrows: I80F48Dto,
lastUpdated: BN,
util0: I80F48Dto,
rate0: I80F48Dto,
util1: I80F48Dto,
rate1: I80F48Dto,
maxRate: I80F48Dto,
collectedFeesNative: I80F48Dto,
loanOriginationFeeRate: I80F48Dto,
loanFeeRate: I80F48Dto,
maintAssetWeight: I80F48Dto,
initAssetWeight: I80F48Dto,
maintLiabWeight: I80F48Dto,
initLiabWeight: I80F48Dto,
liquidationFee: I80F48Dto,
dust: Object,
public tokenIndex: number,
public mintDecimals: number,
) {
this.name = utf8.decode(new Uint8Array(name)).split('\x00')[0];
this.depositIndex = I80F48.from(depositIndex);
this.borrowIndex = I80F48.from(borrowIndex);
this.cachedIndexedTotalDeposits = I80F48.from(indexedTotalDeposits);
this.cachedIndexedTotalBorrows = I80F48.from(indexedTotalBorrows);
this.maxRate = I80F48.from(maxRate);
this.util0 = I80F48.from(util0);
this.rate0 = I80F48.from(rate0);
this.util1 = I80F48.from(util1);
this.rate1 = I80F48.from(rate1);
this.maintAssetWeight = I80F48.from(maintAssetWeight);
this.initAssetWeight = I80F48.from(initAssetWeight);
this.maintLiabWeight = I80F48.from(maintLiabWeight);
this.initLiabWeight = I80F48.from(initLiabWeight);
this.liquidationFee = I80F48.from(liquidationFee);
this.price = undefined;
}
toString(): string {
return (
'Bank ' +
'\n token index -' +
this.tokenIndex +
'\n deposit index -' +
this.depositIndex.toNumber() +
'\n borrow index -' +
this.borrowIndex.toNumber() +
'\n cachedIndexedTotalDeposits -' +
this.cachedIndexedTotalDeposits.toNumber() +
'\n cachedIndexedTotalBorrows -' +
this.cachedIndexedTotalBorrows.toNumber() +
'\n maxRate -' +
this.maxRate.toNumber() +
'\n util0 -' +
this.util0.toNumber() +
'\n rate0 -' +
this.rate0.toNumber() +
'\n util1 -' +
this.util1.toNumber() +
'\n rate1 -' +
this.rate1.toNumber() +
'\n maintAssetWeight -' +
this.maintAssetWeight.toNumber() +
'\n initAssetWeight -' +
this.initAssetWeight.toNumber() +
'\n maintLiabWeight -' +
this.maintLiabWeight.toNumber() +
'\n initLiabWeight -' +
this.initLiabWeight.toNumber() +
'\n liquidationFee -' +
this.liquidationFee.toNumber()
);
}
nativeDeposits(): I80F48 {
return this.cachedIndexedTotalDeposits.mul(this.depositIndex);
}
nativeBorrows(): I80F48 {
return this.cachedIndexedTotalBorrows.mul(this.borrowIndex);
}
uiDeposits(): number {
return nativeI80F48ToUi(
this.cachedIndexedTotalDeposits.mul(this.depositIndex),
this.mintDecimals,
).toNumber();
}
uiBorrows(): number {
return nativeI80F48ToUi(
this.cachedIndexedTotalBorrows.mul(this.borrowIndex),
this.mintDecimals,
).toNumber();
}
getBorrowRate(): I80F48 {
const totalBorrows = this.nativeBorrows();
const totalDeposits = this.nativeDeposits();
if (totalDeposits.eq(ZERO_I80F48) && totalBorrows.eq(ZERO_I80F48)) {
return ZERO_I80F48;
}
if (totalDeposits.lte(totalBorrows)) {
return this.maxRate;
}
const utilization = totalBorrows.div(totalDeposits);
if (utilization.gt(this.util1)) {
const extraUtil = utilization.sub(this.util1);
const slope = this.maxRate
.sub(this.rate1)
.div(I80F48.fromNumber(1).sub(this.util1));
return this.rate1.add(slope.mul(extraUtil));
} else if (utilization.gt(this.util0)) {
const extraUtil = utilization.sub(this.util0);
const slope = this.maxRate
.sub(this.rate0)
.div(I80F48.fromNumber(1).sub(this.util0));
return this.rate0.add(slope.mul(extraUtil));
} else {
const slope = this.rate0.div(this.util0);
return slope.mul(utilization);
}
}
getDepositRate(): I80F48 {
const borrowRate = this.getBorrowRate();
const totalBorrows = this.nativeBorrows();
const totalDeposits = this.nativeDeposits();
if (totalDeposits.eq(ZERO_I80F48) && totalBorrows.eq(ZERO_I80F48)) {
return ZERO_I80F48;
} else if (totalDeposits.eq(ZERO_I80F48)) {
return this.maxRate;
}
const utilization = totalBorrows.div(totalDeposits);
return utilization.mul(borrowRate);
}
}
export class MintInfo {
static from(
publicKey: PublicKey,
obj: {
mint: PublicKey;
banks: PublicKey[];
vaults: PublicKey[];
oracle: PublicKey;
addressLookupTable: PublicKey;
tokenIndex: number;
addressLookupTableBankIndex: Number;
addressLookupTableOracleIndex: Number;
reserved: unknown;
},
) {
return new MintInfo(
publicKey,
obj.mint,
obj.banks,
obj.vaults,
obj.oracle,
obj.tokenIndex,
);
}
constructor(
public publicKey: PublicKey,
public mint: PublicKey,
public banks: PublicKey[],
public vaults: PublicKey[],
public oracle: PublicKey,
public tokenIndex: number,
) {}
public firstBank(): PublicKey {
return this.banks[0];
}
public firstVault(): PublicKey {
return this.vaults[0];
}
toString(): string {
let res =
'mint ' +
this.mint.toBase58() +
'\n oracle ' +
this.oracle.toBase58() +
'\n banks ' +
this.banks
.filter((pk) => pk.toBase58() !== PublicKey.default.toBase58())
.toString() +
'\n vaults ' +
this.vaults
.filter((pk) => pk.toBase58() !== PublicKey.default.toBase58())
.toString();
return res;
}
}