UNPKG

@kamino-finance/kliquidity-sdk

Version:

Typescript SDK for interacting with the Kamino Liquidity (kliquidity) protocol

241 lines (223 loc) 8.22 kB
/* 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 "../types" // eslint-disable-line @typescript-eslint/no-unused-vars import { PROGRAM_ID } from "../programId" export interface PositionFields { /** The LB pair of this position */ lbPair: Address /** Owner of the position. Client rely on this to to fetch their positions. */ owner: Address /** Liquidity shares of this position in bins (lower_bin_id <-> upper_bin_id). This is the same as LP concept. */ liquidityShares: Array<BN> /** Farming reward information */ rewardInfos: Array<types.UserRewardInfoFields> /** Swap fee to claim information */ feeInfos: Array<types.FeeInfoFields> /** Lower bin ID */ lowerBinId: number /** Upper bin ID */ upperBinId: number /** Last updated timestamp */ lastUpdatedAt: BN /** Total claimed token fee X */ totalClaimedFeeXAmount: BN /** Total claimed token fee Y */ totalClaimedFeeYAmount: BN /** Total claimed rewards */ totalClaimedRewards: Array<BN> /** Reserved space for future use */ reserved: Array<number> } export interface PositionJSON { /** The LB pair of this position */ lbPair: string /** Owner of the position. Client rely on this to to fetch their positions. */ owner: string /** Liquidity shares of this position in bins (lower_bin_id <-> upper_bin_id). This is the same as LP concept. */ liquidityShares: Array<string> /** Farming reward information */ rewardInfos: Array<types.UserRewardInfoJSON> /** Swap fee to claim information */ feeInfos: Array<types.FeeInfoJSON> /** Lower bin ID */ lowerBinId: number /** Upper bin ID */ upperBinId: number /** Last updated timestamp */ lastUpdatedAt: string /** Total claimed token fee X */ totalClaimedFeeXAmount: string /** Total claimed token fee Y */ totalClaimedFeeYAmount: string /** Total claimed rewards */ totalClaimedRewards: Array<string> /** Reserved space for future use */ reserved: Array<number> } export class Position { /** The LB pair of this position */ readonly lbPair: Address /** Owner of the position. Client rely on this to to fetch their positions. */ readonly owner: Address /** Liquidity shares of this position in bins (lower_bin_id <-> upper_bin_id). This is the same as LP concept. */ readonly liquidityShares: Array<BN> /** Farming reward information */ readonly rewardInfos: Array<types.UserRewardInfo> /** Swap fee to claim information */ readonly feeInfos: Array<types.FeeInfo> /** Lower bin ID */ readonly lowerBinId: number /** Upper bin ID */ readonly upperBinId: number /** Last updated timestamp */ readonly lastUpdatedAt: BN /** Total claimed token fee X */ readonly totalClaimedFeeXAmount: BN /** Total claimed token fee Y */ readonly totalClaimedFeeYAmount: BN /** Total claimed rewards */ readonly totalClaimedRewards: Array<BN> /** Reserved space for future use */ readonly reserved: Array<number> static readonly discriminator = Buffer.from([ 170, 188, 143, 228, 122, 64, 247, 208, ]) static readonly layout = borsh.struct<Position>([ borshAddress("lbPair"), borshAddress("owner"), borsh.array(borsh.u64(), 70, "liquidityShares"), borsh.array(types.UserRewardInfo.layout(), 70, "rewardInfos"), borsh.array(types.FeeInfo.layout(), 70, "feeInfos"), borsh.i32("lowerBinId"), borsh.i32("upperBinId"), borsh.i64("lastUpdatedAt"), borsh.u64("totalClaimedFeeXAmount"), borsh.u64("totalClaimedFeeYAmount"), borsh.array(borsh.u64(), 2, "totalClaimedRewards"), borsh.array(borsh.u8(), 160, "reserved"), ]) constructor(fields: PositionFields) { this.lbPair = fields.lbPair this.owner = fields.owner this.liquidityShares = fields.liquidityShares this.rewardInfos = fields.rewardInfos.map( (item) => new types.UserRewardInfo({ ...item }) ) this.feeInfos = fields.feeInfos.map( (item) => new types.FeeInfo({ ...item }) ) this.lowerBinId = fields.lowerBinId this.upperBinId = fields.upperBinId this.lastUpdatedAt = fields.lastUpdatedAt this.totalClaimedFeeXAmount = fields.totalClaimedFeeXAmount this.totalClaimedFeeYAmount = fields.totalClaimedFeeYAmount this.totalClaimedRewards = fields.totalClaimedRewards this.reserved = fields.reserved } static async fetch( rpc: Rpc<GetAccountInfoApi>, address: Address, programId: Address = PROGRAM_ID ): Promise<Position | 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<Position | 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): Position { if (!data.slice(0, 8).equals(Position.discriminator)) { throw new Error("invalid account discriminator") } const dec = Position.layout.decode(data.slice(8)) return new Position({ lbPair: dec.lbPair, owner: dec.owner, liquidityShares: dec.liquidityShares, rewardInfos: dec.rewardInfos.map( ( item: any /* eslint-disable-line @typescript-eslint/no-explicit-any */ ) => types.UserRewardInfo.fromDecoded(item) ), feeInfos: dec.feeInfos.map( ( item: any /* eslint-disable-line @typescript-eslint/no-explicit-any */ ) => types.FeeInfo.fromDecoded(item) ), lowerBinId: dec.lowerBinId, upperBinId: dec.upperBinId, lastUpdatedAt: dec.lastUpdatedAt, totalClaimedFeeXAmount: dec.totalClaimedFeeXAmount, totalClaimedFeeYAmount: dec.totalClaimedFeeYAmount, totalClaimedRewards: dec.totalClaimedRewards, reserved: dec.reserved, }) } toJSON(): PositionJSON { return { lbPair: this.lbPair, owner: this.owner, liquidityShares: this.liquidityShares.map((item) => item.toString()), rewardInfos: this.rewardInfos.map((item) => item.toJSON()), feeInfos: this.feeInfos.map((item) => item.toJSON()), lowerBinId: this.lowerBinId, upperBinId: this.upperBinId, lastUpdatedAt: this.lastUpdatedAt.toString(), totalClaimedFeeXAmount: this.totalClaimedFeeXAmount.toString(), totalClaimedFeeYAmount: this.totalClaimedFeeYAmount.toString(), totalClaimedRewards: this.totalClaimedRewards.map((item) => item.toString() ), reserved: this.reserved, } } static fromJSON(obj: PositionJSON): Position { return new Position({ lbPair: address(obj.lbPair), owner: address(obj.owner), liquidityShares: obj.liquidityShares.map((item) => new BN(item)), rewardInfos: obj.rewardInfos.map((item) => types.UserRewardInfo.fromJSON(item) ), feeInfos: obj.feeInfos.map((item) => types.FeeInfo.fromJSON(item)), lowerBinId: obj.lowerBinId, upperBinId: obj.upperBinId, lastUpdatedAt: new BN(obj.lastUpdatedAt), totalClaimedFeeXAmount: new BN(obj.totalClaimedFeeXAmount), totalClaimedFeeYAmount: new BN(obj.totalClaimedFeeYAmount), totalClaimedRewards: obj.totalClaimedRewards.map((item) => new BN(item)), reserved: obj.reserved, }) } }