@kamino-finance/klend-sdk
Version:
Typescript SDK for interacting with the Kamino Lending (klend) protocol
241 lines (228 loc) • 10.2 kB
text/typescript
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
address,
Address,
fetchEncodedAccount,
fetchEncodedAccounts,
GetAccountInfoApi,
GetMultipleAccountsApi,
Rpc,
} from "@solana/kit"
/* eslint-enable @typescript-eslint/no-unused-vars */
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 { borshAddress } from "../utils" // eslint-disable-line @typescript-eslint/no-unused-vars
import * as types from "../../../@codegen/klend/types" // eslint-disable-line @typescript-eslint/no-unused-vars
import { PROGRAM_ID } from "../../../@codegen/klend/programId"
import { Obligation, ObligationFields } from '../../../@codegen/klend/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: Address
/** Owner authority which can borrow liquidity */
readonly owner: Address
/** 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 paddingDeprecatedAssetTiers: 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: Address
/** 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, permissionlessly-executed repay orders.
* Typical use-cases would be a stop-loss and a take-profit (possibly co-existing).
*/
readonly obligationOrders: Array<types.ObligationOrder>
/**
* Owner-defined, permissionlessly-executed borrow order applicable to this obligation.
* Non-zeroed only on a newly-initialized fixed-rate, fixed-term obligation.
*/
readonly borrowOrder: types.BorrowOrder
readonly padding3: Array<BN> = new Array(0)
static readonly layout = borsh.struct<ObligationZP>([
borsh.u64("tag"),
types.LastUpdate.layout("lastUpdate"),
borshAddress("lendingMarket"),
borshAddress("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(), 13, "paddingDeprecatedAssetTiers"),
borsh.u8("elevationGroup"),
borsh.u8("numOfObsoleteDepositReserves"),
borsh.u8("hasDebt"),
borshAddress("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, "obligationOrders"),
types.BorrowOrder.layout("borrowOrder"),
])
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.paddingDeprecatedAssetTiers = fields.paddingDeprecatedAssetTiers
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.obligationOrders = fields.obligationOrders.map(
(item) => new types.ObligationOrder({ ...item })
)
this.borrowOrder = new types.BorrowOrder({ ...fields.borrowOrder })
this.padding3 = new Array<BN>(0);
}
static async fetch(
rpc: Rpc<GetAccountInfoApi>,
address: Address,
programId: Address = PROGRAM_ID
): Promise<Obligation | null> {
const info = await fetchEncodedAccount(rpc, address)
if (!info.exists) {
return null
}
if (info.programAddress !== programId) {
throw new Error("account doesn't belong to this program")
}
return this.decode(Buffer.from(info.data))
}
static async fetchMultiple(
rpc: Rpc<GetMultipleAccountsApi>,
addresses: Address[],
programId: Address = PROGRAM_ID
): Promise<Array<Obligation | null>> {
const infos = await fetchEncodedAccounts(rpc, addresses)
return infos.map((info) => {
if (!info.exists) {
return null
}
if (info.programAddress !== programId) {
throw new Error("account doesn't belong to this program")
}
return this.decode(Buffer.from(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,
paddingDeprecatedAssetTiers: dec.paddingDeprecatedAssetTiers,
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,
obligationOrders: dec.obligationOrders.map(
(
item: any /* eslint-disable-line @typescript-eslint/no-explicit-any */
) => types.ObligationOrder.fromDecoded(item)
),
borrowOrder: types.BorrowOrder.fromDecoded(dec.borrowOrder),
padding3: [],
})
}
}