UNPKG

@kamino-finance/klend-sdk

Version:

Typescript SDK for interacting with the Kamino Lending (klend) protocol

228 lines (200 loc) 6.13 kB
import { Address, getAddressEncoder, getProgramDerivedAddress, isNone, none, Option } from '@solana/kit'; import { KaminoMarket, KaminoObligation } from '../classes'; import { DEFAULT_PUBLIC_KEY } from './pubkey'; const addressEncoder = getAddressEncoder(); export type ObligationType = VanillaObligation | MultiplyObligation | LendingObligation | LeverageObligation; export enum ObligationTypeTag { Vanilla = 0, Multiply = 1, Lending = 2, Leverage = 3, } export type InitObligationArgsModel = { tag: number; id: number; seed1: Address; seed2: Address; }; export class VanillaObligation { readonly programId: Address; readonly id: number; static tag = 0; constructor(programId: Address, id?: number) { this.programId = programId; this.id = id ?? 0; } toArgs() { const initObligationArgs: InitObligationArgsModel = { tag: VanillaObligation.tag, id: this.id, seed1: DEFAULT_PUBLIC_KEY, seed2: DEFAULT_PUBLIC_KEY, }; return initObligationArgs; } toPda(market: Address, user: Address) { return getObligationPdaWithArgs(market, user, this.toArgs(), this.programId); } } export class MultiplyObligation { readonly collToken: Address; readonly debtToken: Address; readonly programId: Address; readonly id: number; static tag = 1; constructor(collToken: Address, debtToken: Address, programId: Address, id?: number) { this.collToken = collToken; this.debtToken = debtToken; this.programId = programId; this.id = id ?? 0; } toArgs() { const initObligationArgs: InitObligationArgsModel = { tag: MultiplyObligation.tag, id: this.id, seed1: this.collToken, seed2: this.debtToken, }; return initObligationArgs; } toPda(market: Address, user: Address) { return getObligationPdaWithArgs(market, user, this.toArgs(), this.programId); } } export class LeverageObligation { readonly collToken: Address; readonly debtToken: Address; readonly programId: Address; readonly id: number; static tag = 3; constructor(collToken: Address, debtToken: Address, programId: Address, id?: number) { this.collToken = collToken; this.debtToken = debtToken; this.programId = programId; this.id = id ?? 0; } toArgs() { const initObligationArgs: InitObligationArgsModel = { tag: LeverageObligation.tag, id: this.id, seed1: this.collToken, seed2: this.debtToken, }; return initObligationArgs; } toPda(market: Address, user: Address) { return getObligationPdaWithArgs(market, user, this.toArgs(), this.programId); } } export class LendingObligation { readonly token: Address; readonly programId: Address; readonly id: number; static tag = 2; constructor(token: Address, programId: Address, id?: number) { this.token = token; this.programId = programId; this.id = id ?? 0; } toArgs() { const initObligationArgs: InitObligationArgsModel = { tag: LendingObligation.tag, id: 0, seed1: this.token, seed2: this.token, }; return initObligationArgs; } toPda(market: Address, user: Address) { return getObligationPdaWithArgs(market, user, this.toArgs(), this.programId); } } export async function getObligationPdaWithArgs( market: Address, user: Address, args: InitObligationArgsModel, programId: Address ): Promise<Address> { const seeds = [ Buffer.from([args.tag]), Buffer.from([args.id]), addressEncoder.encode(user), addressEncoder.encode(market), addressEncoder.encode(args.seed1), addressEncoder.encode(args.seed2), ]; const [obligationAddress, _obligationAddressBump] = await getProgramDerivedAddress({ seeds, programAddress: programId, }); return obligationAddress; } export function getObligationType( kaminoMarket: KaminoMarket, obligationTag: ObligationTypeTag, mintAddress1: Option<Address> = none(), mintAddress2: Option<Address> = none() ): ObligationType { switch (obligationTag) { case VanillaObligation.tag: { return new VanillaObligation(kaminoMarket.programId); } case MultiplyObligation.tag: { if (isNone(mintAddress1)) { throw new Error(`Multiply obligation PDA requires mint address 1`); } if (isNone(mintAddress2)) { throw new Error(`Multiply obligation PDA requires mint address 2`); } return new MultiplyObligation(mintAddress1.value, mintAddress2.value, kaminoMarket.programId); } case LeverageObligation.tag: { if (isNone(mintAddress1)) { throw new Error(`Leverage obligation PDA requires mint address 1`); } if (isNone(mintAddress2)) { throw new Error(`Leverage obligation PDA requires mint address 2`); } return new LeverageObligation(mintAddress1.value, mintAddress2.value, kaminoMarket.programId); } case LendingObligation.tag: { if (isNone(mintAddress1)) { throw new Error(`Lending obligation PDA requires mint address 1`); } return new LendingObligation(mintAddress1.value, kaminoMarket.programId); } default: { throw new Error('Invalid obligation type'); } } } export function getObligationTypeFromObligation( kaminoMarket: KaminoMarket, obligation: KaminoObligation ): ObligationType { switch (obligation.obligationTag) { case VanillaObligation.tag: { return new VanillaObligation(kaminoMarket.programId); } case MultiplyObligation.tag: { return new MultiplyObligation( obligation.getDeposits()[0].mintAddress, obligation.getBorrows()[0].mintAddress, kaminoMarket.programId ); } case LeverageObligation.tag: { return new LeverageObligation( obligation.getDeposits()[0].mintAddress, obligation.getBorrows()[0].mintAddress, kaminoMarket.programId ); } case LendingObligation.tag: { return new LendingObligation(obligation.getDeposits()[0].mintAddress, kaminoMarket.programId); } default: { throw new Error('Invalid obligation type'); } } }