@kamino-finance/klend-sdk
Version:
Typescript SDK for interacting with the Kamino Lending (klend) protocol
229 lines (217 loc) • 9.58 kB
text/typescript
import { PublicKey, Connection } from "@solana/web3.js"
import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars
import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars
import { PROGRAM_ID } from "../programId"
import { Obligation, ObligationFields } from '../accounts';
/** Lending market obligation state */
export class ObligationZP {
/** Version of the struct */
readonly tag: BN
/** Last update to collateral, liquidity, or their market values */
readonly lastUpdate: types.LastUpdate
/** Lending market address */
readonly lendingMarket: PublicKey
/** Owner authority which can borrow liquidity */
readonly owner: PublicKey
/**
* TODO: Does this break the stack size when copied onto the stack, if too big?
* Deposited collateral for the obligation, unique by deposit reserve address
*/
readonly deposits: Array<types.ObligationCollateral>
/** Worst LTV for the collaterals backing the loan, represented as a percentage */
readonly lowestReserveDepositLiquidationLtv: BN
/** Market value of deposits (scaled fraction) */
readonly depositedValueSf: BN
/** Borrowed liquidity for the obligation, unique by borrow reserve address */
readonly borrows: Array<types.ObligationLiquidity>
/** Risk adjusted market value of borrows/debt (sum of price * borrowed_amount * borrow_factor) (scaled fraction) */
readonly borrowFactorAdjustedDebtValueSf: BN
/** Market value of borrows - used for max_liquidatable_borrowed_amount (scaled fraction) */
readonly borrowedAssetsMarketValueSf: BN
/** The maximum borrow value at the weighted average loan to value ratio (scaled fraction) */
readonly allowedBorrowValueSf: BN
/** The dangerous borrow value at the weighted average liquidation threshold (scaled fraction) */
readonly unhealthyBorrowValueSf: BN
/** The asset tier of the deposits */
readonly depositsAssetTiers: Array<number>
/** The asset tier of the borrows */
readonly borrowsAssetTiers: Array<number>
/** The elevation group id the obligation opted into. */
readonly elevationGroup: number
/** The number of obsolete reserves the obligation has a deposit in */
readonly numOfObsoleteDepositReserves: number
/** Marked = 1 if borrows array is not empty, 0 = borrows empty */
readonly hasDebt: number
/** Wallet address of the referrer */
readonly referrer: PublicKey
/** Marked = 1 if borrowing disabled, 0 = borrowing enabled */
readonly borrowingDisabled: number
/**
* A target LTV set by the risk council when marking this obligation for deleveraging.
* Only effective when `deleveraging_margin_call_started_slot != 0`.
*/
readonly autodeleverageTargetLtvPct: number
/** The lowest max LTV found amongst the collateral deposits */
readonly lowestReserveDepositMaxLtvPct: number
/** The number of obsolete reserves the obligation has a borrow in */
readonly numOfObsoleteBorrowReserves: number
readonly reserved: Array<number>
readonly highestBorrowFactorPct: BN
/**
* A timestamp at which the risk council most-recently marked this obligation for deleveraging.
* Zero if not currently subject to deleveraging.
*/
readonly autodeleverageMarginCallStartedTimestamp: BN
/**
* Owner-defined, liquidator-executed orders applicable to this obligation.
* Typical use-cases would be a stop-loss and a take-profit (possibly co-existing).
*/
readonly orders: Array<types.ObligationOrder>
readonly padding3: Array<BN> = new Array(0)
static readonly layout = borsh.struct([
borsh.u64("tag"),
types.LastUpdate.layout("lastUpdate"),
borsh.publicKey("lendingMarket"),
borsh.publicKey("owner"),
borsh.array(types.ObligationCollateral.layout(), 8, "deposits"),
borsh.u64("lowestReserveDepositLiquidationLtv"),
borsh.u128("depositedValueSf"),
borsh.array(types.ObligationLiquidity.layout(), 5, "borrows"),
borsh.u128("borrowFactorAdjustedDebtValueSf"),
borsh.u128("borrowedAssetsMarketValueSf"),
borsh.u128("allowedBorrowValueSf"),
borsh.u128("unhealthyBorrowValueSf"),
borsh.array(borsh.u8(), 8, "depositsAssetTiers"),
borsh.array(borsh.u8(), 5, "borrowsAssetTiers"),
borsh.u8("elevationGroup"),
borsh.u8("numOfObsoleteDepositReserves"),
borsh.u8("hasDebt"),
borsh.publicKey("referrer"),
borsh.u8("borrowingDisabled"),
borsh.u8("autodeleverageTargetLtvPct"),
borsh.u8("lowestReserveDepositMaxLtvPct"),
borsh.u8("numOfObsoleteBorrowReserves"),
borsh.array(borsh.u8(), 4, "reserved"),
borsh.u64("highestBorrowFactorPct"),
borsh.u64("autodeleverageMarginCallStartedTimestamp"),
borsh.array(types.ObligationOrder.layout(), 2, "orders"),
])
constructor(fields: ObligationFields) {
this.tag = fields.tag
this.lastUpdate = new types.LastUpdate({ ...fields.lastUpdate })
this.lendingMarket = fields.lendingMarket
this.owner = fields.owner
this.deposits = fields.deposits.map(
(item) => new types.ObligationCollateral({ ...item })
)
this.lowestReserveDepositLiquidationLtv =
fields.lowestReserveDepositLiquidationLtv
this.depositedValueSf = fields.depositedValueSf
this.borrows = fields.borrows.map(
(item) => new types.ObligationLiquidity({ ...item })
)
this.borrowFactorAdjustedDebtValueSf =
fields.borrowFactorAdjustedDebtValueSf
this.borrowedAssetsMarketValueSf = fields.borrowedAssetsMarketValueSf
this.allowedBorrowValueSf = fields.allowedBorrowValueSf
this.unhealthyBorrowValueSf = fields.unhealthyBorrowValueSf
this.depositsAssetTiers = fields.depositsAssetTiers
this.borrowsAssetTiers = fields.borrowsAssetTiers
this.elevationGroup = fields.elevationGroup
this.numOfObsoleteDepositReserves = fields.numOfObsoleteDepositReserves
this.hasDebt = fields.hasDebt
this.referrer = fields.referrer
this.borrowingDisabled = fields.borrowingDisabled
this.autodeleverageTargetLtvPct = fields.autodeleverageTargetLtvPct
this.lowestReserveDepositMaxLtvPct = fields.lowestReserveDepositMaxLtvPct
this.numOfObsoleteBorrowReserves = fields.numOfObsoleteBorrowReserves
this.reserved = new Array<number>(0)
this.highestBorrowFactorPct = fields.highestBorrowFactorPct
this.autodeleverageMarginCallStartedTimestamp =
fields.autodeleverageMarginCallStartedTimestamp
this.orders = fields.orders.map(
(item) => new types.ObligationOrder({ ...item })
)
this.padding3 = new Array<BN>(0);
}
static async fetch(
c: Connection,
address: PublicKey,
programId: PublicKey = PROGRAM_ID
): Promise<Obligation | null> {
const info = await c.getAccountInfo(address)
if (info === null) {
return null
}
if (!info.owner.equals(programId)) {
throw new Error("account doesn't belong to this program")
}
return this.decode(info.data)
}
static async fetchMultiple(
c: Connection,
addresses: PublicKey[],
programId: PublicKey = PROGRAM_ID
): Promise<Array<Obligation | null>> {
const infos = await c.getMultipleAccountsInfo(addresses)
return infos.map((info) => {
if (info === null) {
return null
}
if (!info.owner.equals(programId)) {
throw new Error("account doesn't belong to this program")
}
return this.decode(info.data)
})
}
static decode(data: Buffer): Obligation {
if (!data.slice(0, 8).equals(Obligation.discriminator)) {
throw new Error("invalid account discriminator")
}
const dec = ObligationZP.layout.decode(data.slice(8))
return new Obligation({
tag: dec.tag,
lastUpdate: types.LastUpdate.fromDecoded(dec.lastUpdate),
lendingMarket: dec.lendingMarket,
owner: dec.owner,
deposits: dec.deposits.map(
(
item: any /* eslint-disable-line @typescript-eslint/no-explicit-any */
) => types.ObligationCollateral.fromDecoded(item)
),
lowestReserveDepositLiquidationLtv:
dec.lowestReserveDepositLiquidationLtv,
depositedValueSf: dec.depositedValueSf,
borrows: dec.borrows.map(
(
item: any /* eslint-disable-line @typescript-eslint/no-explicit-any */
) => types.ObligationLiquidity.fromDecoded(item)
),
borrowFactorAdjustedDebtValueSf: dec.borrowFactorAdjustedDebtValueSf,
borrowedAssetsMarketValueSf: dec.borrowedAssetsMarketValueSf,
allowedBorrowValueSf: dec.allowedBorrowValueSf,
unhealthyBorrowValueSf: dec.unhealthyBorrowValueSf,
depositsAssetTiers: dec.depositsAssetTiers,
borrowsAssetTiers: dec.borrowsAssetTiers,
elevationGroup: dec.elevationGroup,
numOfObsoleteDepositReserves: dec.numOfObsoleteDepositReserves,
hasDebt: dec.hasDebt,
referrer: dec.referrer,
borrowingDisabled: dec.borrowingDisabled,
autodeleverageTargetLtvPct: dec.autodeleverageTargetLtvPct,
lowestReserveDepositMaxLtvPct: dec.lowestReserveDepositMaxLtvPct,
numOfObsoleteBorrowReserves: dec.numOfObsoleteBorrowReserves,
reserved: dec.reserved,
highestBorrowFactorPct: dec.highestBorrowFactorPct,
autodeleverageMarginCallStartedTimestamp:
dec.autodeleverageMarginCallStartedTimestamp,
orders: dec.orders.map(
(
item: any /* eslint-disable-line @typescript-eslint/no-explicit-any */
) => types.ObligationOrder.fromDecoded(item)
),
padding3: [],
})
}
}