npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kestrelfi/lyc-sdk

v1.0.3

Published

Client for the long_yield_carry Anchor program: PDA derivation, account decoding, instruction builders, and high-level transaction plans.

Readme

Long Yield Carry TypeScript SDK

Client for the long_yield_carry Anchor program: PDA derivation, account decoding, instruction builders, and high-level transaction plans. The main entry point is LongYieldCarryClient (the “LYC client”).

Installation and import

In this monorepo, depend on the workspace package and use the long-yield-carry path alias (see root tsconfig.json):

import { LongYieldCarryClient } from "@kestrelfi/lyc-sdk";
import { BN } from "@anchor-lang/core";
import { address, type Address } from "@solana/kit";

External consumers install @kestrelfi/lyc-sdk from npm. Two entries:

  • @kestrelfi/lyc-sdk — the full SDK. Requires the optional Kamino peer deps (@kamino-finance/klend-sdk, farms-sdk, scope-sdk) to be installed.
  • @kestrelfi/lyc-sdk/core — browser-safe read + mint/burn surface (account fetchers, PDA derivation, MintTokenBuilder/BurnTokenBuilder, constants, IDL, and the send pipeline). No Kamino/Jupiter graph; this is what frontends should import. See src/core.ts for a usage sketch.

Building and publishing

The manifest is split between two consumers:

  • Inside the monorepo (backend Lambdas, tests), main/types point at src/index.ts — esbuild/tsx bundle the TypeScript source through the pnpm workspace links, no build step required.
  • On npm, publishConfig rewrites main/module/types/exports to dist/ at pack time, and prepack runs tsup to produce it. tsup bundles the unpublished workspace packages (common, lending-platforms, oracle, perena-helpers, swap-aggregator, jupiter-helpers) into dist/ — a consumer installing from npm cannot resolve their file: links, so they must never appear in the published dependencies (they live in devDependencies). Everything declared in dependencies / peerDependencies stays external.

Always release with pnpm publish (or inspect with pnpm pack) from this directory — never npm publish. npm ignores the publishConfig entry-point overrides and would ship a package whose main points at monorepo-only TypeScript source. Sanity-check a release by unpacking the pnpm pack tarball and confirming package.json has dist/ entry points and no file: entries outside devDependencies.

Constructing the client

You need an Anchor AnchorProvider (connection + wallet). The second argument selects the deployment environment and thus the program ID and RPC URL used by the SDK:

import { AnchorProvider } from "@anchor-lang/core";
import { LongYieldCarryClient } from "@kestrelfi/lyc-sdk";

const client = new LongYieldCarryClient(provider, "local");
// or "test" | "prod"

Optional third argument: LongYieldCarryClientOptions — e.g. swapClient or a lendingPlatformClients override for tests or custom routing.

What hangs off the client

| Property | Role | | ------------------------------------------------ | -------------------------------------------------------------------- | | client.pda | Derive Token and YieldingBank PDAs | | client.account | Fetch and cache on-chain accounts (LYCToken, LYCYieldingBank) | | client.ix | Build single Kit Instructions | | client.tx | Build composed transaction plans (ATAs, wraps, refreshes, CPI pools) | | client.rpc | Shared RPC used by send helpers | | client.swap | Aggregate swap client (used by manager flows and some planners) | | client.getLendingPlatformClient(...) | Resolve the lending client for an on-chain lending position | | client.getLendingPlatformClientByPlatform(...) | Resolve a lending client when only the platform enum is known | | client.sendTransaction(...) | Sign, send, confirm, and apply plan cache invalidations |


Minting yTokens (mint_token)

Recommended: client.tx.mintToken.getTx(...)

Use this for end-user flows. It prepends, when needed:

  • SOL collateral: create the user’s wSOL ATA (if missing), transfer lamports from the signer, sync_native.
  • yToken: idempotent ATA creation for the user’s receipt account.

Then it appends mint_token. The signer must be the wallet that owns the collateral and will receive minted yTokens.

import { BN } from "@anchor-lang/core";
import { address } from "@solana/kit";

const signer = address(walletAddress);
const tokenPda = address("…"); // Token PDA

const mintPlan = await client.tx.mintToken.getTx({
  signer,
  token: tokenPda,
  params: {
    depositAmount: new BN(1_000_000_000), // base units, e.g. lamports
  },
});
await client.sendTransaction(walletSigner, mintPlan);

Burning yTokens (burn_token)

Recommended: client.tx.burnToken.getTx(...)

burn_token redeems from unlent collateral when balances suffice at execution time. Without asyncFallback, the SDK sends BurnTokenParams.sync; insufficient unlent balance surfaces as InsufficientUnlentCollateral. Pass asyncFallback (epoch/request PDAs + BurnTokenParams.async) when the same transaction should create or extend an async redemption queue instead.

const burnPlan = await client.tx.burnToken.getTx({
  signer,
  token: tokenPda,
  params: {
    burnAmount: new BN(500_000_000),
  },
});
await client.sendTransaction(walletSigner, burnPlan);

When collateral is native SOL (WSOL), the plan appends a close-account after burn_token so proceeds settle as SOL.

const plainBurn = await client.tx.burnToken.getTx({
  signer,
  token: tokenPda,
  params: {
    burnAmount: new BN(500_000_000),
    // Optional: include a fallback so the same burn_token instruction creates
    // an async request if reserves are short by the time the tx lands.
    asyncFallback: {
      epochId: new BN(7),
      // Omit requestSequence to let the builder read the next epoch sequence.
      requestSequence: new BN(0),
    },
  },
});

Async Burns

Async burns group one or more FIFO requests into a redemption epoch. Users still call burnToken; there is no separate user-facing create/request instruction:

await client.tx.burnToken.getTx({
  signer,
  token: tokenPda,
  params: {
    burnAmount: new BN(500_000_000),
    asyncFallback: {
      epochId: new BN(7),
      requestSequence: new BN(0),
    },
  },
});

Managers fund closed epochs by running decreaseCarryPosition with redemptionEpoch when DCP loss should be charged to that epoch, then topUpUnlentReserves to withdraw freed collateral. processAsyncBurn processes requests in exact sequence order and rejects out-of-order requests.

Reading on-chain state

Token accounts → LYCToken

const token = await client.account.fetchToken(tokenPda);
// token.address — Token PDA
// token.data — raw IDL shape
// token.mint, token.collateralMint, token.decimals
// token.price, token.totalSupply, token.tvlUsd — UI helpers

Batch and discovery:

  • client.account.fetchTokens([pda1, pda2]) — multiple PDAs.
  • client.account.fetchAllTokens() — all Token accounts owned by the program.

Use { fresh: true } to bypass the short-lived in-memory cache when you must see writes immediately:

await client.account.fetchToken(tokenPda, { fresh: true });

Yielding bank accounts → LYCYieldingBank

const bank = await client.account.fetchYieldingBank(yieldingBankPda);
// bank.address, bank.data
// bank.baseMint, bank.defaultRedemptionMint, bank.id, bank.decimals // share decimals, canonical 8
// bank.sharePrice, bank.minSharePrice, bank.totalShares — UI helpers

Also: fetchYieldingBanks([...]), fetchAllYieldingBanks().

User holdings → UserHolding[]

Fetch every LYC yToken a wallet holds, with balances and optional USD notionals when you pass a collateral USD priceMap.

const holdings = await client.account.fetchUserHoldings(walletAddress, {
  priceMap: { [collateralMint]: usdPrice },
});
// holdings[i].token        — LYCToken model (price, label, decimals, …)
// holdings[i].balance      — bigint, base units of the yToken
// holdings[i].uiBalance    — decimal-adjusted number
// holdings[i].valueUsd     — uiBalance × token.price × priceMap[collateralMint], if priced
// holdings[i].tokenAccount — user ATA for the yToken mint

Without a usable entry in priceMap for the collateral mint, valueUsd is omitted (no inference from stale on-chain TVL). Zero-balance holdings are filtered out by default; pass { includeEmpty: true } to include them.

PDAs (when you know mint + id)

const [tokenPda] = await client.pda.deriveTokenPda(yTokenMint, tokenId);
const [bankPda] = await client.pda.deriveYieldingBankPda(baseMint, yieldingBankId);

Seeds match the program: TOKEN + mint + id; YIELDING_BANK + base mint + id.


Sending transactions

client.sendTransaction(payer, planOrInstructions, options?) accepts either a LongYieldCarryTransactionPlan (instructions, lookupTables, optional postSuccessCacheInvalidations) or a bare Instruction[]. When you pass a plan, post-success hooks clear SDK caches for affected Tokens / YieldingBanks plus any Kamino-related invalidations. Use the payer’s Kit TransactionSigner expected by common’s signSendAndConfirmTransaction.

Anchor error codes

The bundled IDL still lists InvalidTvlBiasBps: TVL bias configuration was removed on-chain, but the Anchor error variant is retained so numeric error discriminants do not shift versus older program builds. Match errors using IDL-derived names and regenerate TypeScript bindings when you upgrade the deployed program — do not rely on hard-coded Anchor error integers.