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

@1delta/calldata-sdk-sol

v0.0.11

Published

⚒️ Builds Solana transactions for the lenders the SDK serves — the peer of @1delta/calldata-sdk: same entrypoints, instructions instead of composer calldata, artifacts that expire. No viem, no Solana runtime.

Downloads

1,365

Readme

@1delta/calldata-sdk-sol

Moved from lending-sdks-sol/packages/calldata-sdk on 2026-10-02. Paths are relative to this package; the prototype's @1delta/sol-* names map to @1delta/calldata-sdk-sol, margin-fetcher-sol, svm-kit.

The peer of @1delta/calldata-sdk: the same entrypoints, building Solana transactions instead of composer calldata. What the EVM package encodes for one contract, this one fetches from each lender's hosted builder as instructions, adds what those builders leave out, and seals — a transaction that expires in ~60–90 s, delivered in the SvmTransaction envelope the EVM API already defines for chainType: 'svm'.

There is no composer on Solana (SOLANA_ARCHITECTURE_PLAN §3). The names are kept anyway — ComposerDirectLending.composeDirectMoneyMarketAction, ComposerQuickActions.swapAndDeposit, SvmTxUtilsLite — so the API routes port by import path, the way the tracer ports yield-tracer's ingest.

src/
  types/            SvmCallParams (instructions + tables + splits) ← EVMCallParams; mergeCallParams
  lending/
    types/          LendingOperation, QuickActionType, LendingMode — the EVM shape, reduced
    actions/        KaminoLending (/ktx/klend/*-instructions), JupiterLendLending (/borrow/operate-instructions),
                    SaveLending (the program's OWN instructions — no hosted builder; SAVE_FINANCE.md §3)
    direct/         ComposerDirectLending: the single entrypoint + depositAndBorrow / repayAndWithdraw
    utils/          getLenderData (lender key → market/reserve, vault, or Save market/reserve), toDecimalAmount
    consts/         U64_MAX, MIN_I128, the API bases
  spot/             ComposerSpot.jupiterSwap — Jupiter /swap-instructions, the instruction form
  quickActions/     ComposerQuickActions — swapAndDeposit, swapDepositAndBorrow, swapAndRepay, borrowAndSwap, …
  vaults/           ComposerVaultActions — kvault deposit/withdraw, Jupiter Lend earn deposit/withdraw/mint/redeem
  vaults/exponent/  ComposerExponentActions — Exponent PT trades from the VENDORED IDL, the program as the quoter (EXPONENT.md §3)
  vaults/solstice/  ComposerSolsticeActions — Solstice deposits, the three exits and their claims from the app-bundled IDLs; the program as the quoter by post-simulation balances (SOLSTICE.md §6)
  vaults/huma/      ComposerHumaActions — Huma 2.0 PST deposit (lender setup prepended), the queued redemption and its cancel, the instant withdrawal quoted by simulation (docs/HUMA.md §8)
  txUtils/          SvmTxUtilsLite — assemble: tables, blockhash, pack, simulate, budget, price, seal; `indexPatches` resolve instruction indexes a flash pair carries
  flashloan/        the flash providers (Jupiter Lend's program, Kamino's pair, Save's pair, Project 0's bracket) + `ComposerMargin` — open / close / adjust / migrate a loop on any venue (LOOPING.md)
  lending/actions/loopscale/  the venue-built loop: `/creditbook/flash_borrow` with our swap as its CPI, the returned message enveloped and simulated

One direct action

import {
  ComposerDirectLending,
  QuickActionType,
  LendingMode,
  SvmTxUtilsLite,
} from '@1delta/calldata-sdk-sol'
import { createSvmRpc, createSvmFetchers } from '@1delta/svm-kit'

const bundle = await ComposerDirectLending.composeDirectMoneyMarketAction({
  amount: 10_000_000n, // raw units, as on EVM
  lender: 'KAMINO_7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF',
  chainId: 'solana',
  actionType: QuickActionType.Deposit,
  lendingMode: LendingMode.NONE,
  account: wallet, // signer, fee payer, receiver
  callerAssetAddress: 'So11111111111111111111111111111111111111112',
  lenderAssetAddress: 'd4A2prbA2whesmvHaL88BH6Ewn5N4bTSU2Ze8P6Bc4Q', // the marketUid ref: Kamino's RESERVE
  decimals: 9, // Kamino's builder speaks decimal amounts
})

const fetchers = createSvmFetchers(createSvmRpc())
const { transactions, fees } = await SvmTxUtilsLite.assemble(bundle, {
  fetchers,
  payer: wallet,
})
// transactions[0]: { chainType: 'svm', transaction, lastValidBlockHeight, expiresAt, addressLookupTables, instructions }

isAll on a withdraw / repay sends the lender's own sentinel — Kamino u64::MAX (in decimal form, 18446744073.709551615 at 9 decimals), Jupiter Lend MIN_I128, Save raw u64::MAX (a withdraw's is in cTOKENS; a partial withdraw is converted at the reserve's current exchange rate, floored). Jupiter Lend actions other than a fresh deposit need jupiterLendParams.positionId (positions are NFTs; the user-data layer lists them). Save needs nothing beyond the lender key and the reserve: the obligation is DERIVED from the wallet (saveParams.obligationIndex picks a sub-account) and read from the chain; a wallet with none gets the allocation

  • InitObligation in front of its first deposit.

Save — built from the program, not a builder

SaveLending (actions/save/) has no counterparty to call. It resolves the market's address book from /v1/markets/configs, the wallet's obligation from the chain, and the refresh set from the obligation's own legs, then emits ONE atomic list per action: RefreshReserve × every reserve the obligation touches → RefreshObligation → the action, with the obligation's deposit reserves as trailing accounts in obligation order. Its 11 encoders are pinned byte-exact against @solendprotocol/[email protected] (test/fixtures/save-instructions.json), and test/save.live.test.ts proves the LISTS by simulating a borrow, a withdraw and a fresh-wallet deposit against mainnet through assemble. Before returning, the builder reads the Pyth receiver accounts of the refresh set and refuses (SaveStaleOracleError) when a price is older than 100 s — the program would refuse the refresh at 120 s, and posting a price update is not built. SaveLending.flashLoanPair wraps a body in FlashBorrow … FlashRepay(index); both must stay top-level (the program rejects CPI) and index is the borrow's ABSOLUTE position in the transaction. Only the assembler knows that (it prepends one ComputeBudget instruction on the simulation probe and two on the sealed message, and drops duplicate idempotent ATA creates), so a builder never writes it: it emits the bundle-relative index plus an indexPatches entry ({ ix, dataOffset, target, width }) and assemble rewrites the bytes per segment — refusing a bracket that would span a cut. Project 0's start_flashloan(end_index) is the same mechanism with a u64. Both pairs are simulated on mainnet through it (save.live.test.ts, project0.live.test.ts).

Huma — the queue's id and the instant path

ComposerHumaActions (vaults/huma/) encodes from the recovered on-chain IDL. Three facts the program never states in it, each pinned by a test: a new redemption request's id is last_request_id + 1 (next_request_id is the processor's FIFO head — an existing request's id whenever the queue is non-empty); the request PDA seed is the u128 id big-endian; and a wallet without a LenderState needs create_lender_accounts_v2 before its first deposit (the builder reads the state and prepends it). The instant exit is permissionless with a progressive fee by liquid-asset ratio, so instantWithdraw quotes it by running it (quoteInstantWithdraw, the Solstice quoter's mechanism) and seals with max_fee = quote × (1 + tolerance). ComposerVaultActions routes provider: 'huma' for deposit and redeemShares; test/huma.live.test.ts simulates all three paths on mainnet.

What the hosted builders do and do not do

| | Kamino /ktx/*-instructions | Jupiter Lend /borrow/operate-instructions | | ----------------------------- | ----------------------------------- | --------------------------------------------------------------------- | | amount | decimal string | raw, signed (+ deposit/borrow, − withdraw/repay) | | ATA creation, SOL wrap/unwrap | included | absent — this package adds them (actions/jupiter-lend/setup.ts) | | compute-unit limit | included (stripped, we set our own) | absent | | priority fee | absent | absent | | lookup tables | contents included (lutsByAddress) | addresses only — resolved by RPC | | one-shot (deposit + borrow) | two lists, concatenated | one operate with both legs | | "all" sentinel | u64::MAX | MIN_I128 per side |

Measured 2026-09-16 (fixtures in test/fixtures/). Jupiter Lend's builder simulates to learn a fresh position's nftId, so the signer must hold SOL; a wallet that cannot run the transaction answers {"message":"No return data found in logs"}.

Composed actions and the byte cap

A quick action is a concatenation: swap leg, lending leg(s), each from its own builder, with a split recorded at every boundary. The assembler packs greedily — as many instructions as fit in 1,232 bytes and 64 account locks — and cuts only at a split; a swap → Kamino deposit fit in one 928-byte transaction live (tables carry it), a cut is the fallback and Assembled.split plus the description suffix (i/n) say so. A segment that depends on an earlier one (a deposit of a swap's output) cannot be simulated by the chain; it is budgeted at fallbackComputeUnits and the fee report says simulated: false.

The lending leg is sized on the swap's guaranteed output (otherAmountThreshold for ExactIn, outAmount for ExactOut) because a hosted lender instruction takes a fixed amount — there is no "deposit the contract balance". The surplus stays in the wallet. Prefer ExactOut quotes for a repay.

Fee policy

SvmFeePolicy in svm-kit/fees.ts: simulate → unitsConsumed × (1 + margin) → getRecentPrioritizationFees over the transaction's writable accounts → the median sample, floored at 1 000 µL/CU, capped at 2 M, and a hard cap of 0.02 SOL on the priority fee (refused, not clipped). Every number is overridable per call.

Testing

  • pnpm test — offline. The hosted builders' responses are fixtures; the message compiler is proven against them in svm-kit (both venues serve the same request sealed and unsealed, and our compile of their instructions is byte-identical to their transaction — order: 'address' for Kamino's @solana/kit, first-appearance for Jupiter's web3.js).
  • pnpm test:live — the builders and a public RPC: Kamino deposit, Jupiter Lend deposit with our setup, swap → deposit; each assembled, simulated and budgeted. Nothing is sent.

Exponent — a venue with no hosted builder

Exponent (Pendle on Solana) publishes no quote or build endpoint; its SDK is AGPL on web3.js. So this package builds the leg itself: the CLMM and core IDLs are vendored (vaults/exponent/idl/, the ABI, address-pinned), MarketThree / Vault decode through svm-kit's IDL codec, and trade_pt / trade_pt_exact_out / buy_pt / sell_pt are encoded from the IDL with every account taken off the market account (the SY program's CPI accounts are ALT indexes on it).

import {
  ComposerExponentActions,
  readMarketThree,
} from '@1delta/calldata-sdk-sol'

const market = await readMarketThree(fetchers, clmmMarket) // from the tracer's exponent_meta.market_address
const q = await ComposerExponentActions.quote(
  { market, direction: 'SyToPt', amountIn: 1_000_000_000n }, // no wallet needed: runs as the pool
  { fetchers },
)
// q = { amountOut: 1014764897n, exact: true, source: 'simulation', ptPriceInSy: 0.98545, unitsConsumed: 127806 }
const leg = await ComposerExponentActions.tradePt(
  {
    market: clmmMarket,
    account: wallet,
    direction: 'SyToPt',
    amountIn: q.amountIn,
    amountConstraint: (q.amountOut * 995n) / 1000n,
  }, // 50 bps
  { fetchers, market },
)
const { transactions } = await SvmTxUtilsLite.assemble(leg, {
  fetchers,
  payer: wallet,
})

The quote IS a simulation of the instruction: trade_pt returns TradePtReturnData and the RPC hands it back, so fees, tick crossings and spot limits are the program's own. A size-only quote borrows the pool's identity (sigVerify: false), a wallet quote runs as the wallet. midQuote is the no-RPC estimate off the API mid, marked exact: false. buy_pt / sell_pt (base ↔ PT) are encoded but not yet simulation-verified on a funded wallet — EXPONENT.md §4.

Solstice — three exits, one composer

Solstice (USX yield tokens: eUSX, SR-/JR-strcUSX) publishes no IDL and no public builder; the app bundles both programs' IDLs and those are vendored (@1delta/margin-fetcher-sol's vaults/solstice/idl/). Every user instruction is encoded from them and checked against them position by position in test/solstice.test.ts. What makes the composer more than an encoder is the exit: eUSX unlocks into a 7-day escrow, senior leaves instantly at a fee or through a 15-day cooldown, junior queues into a settlement batch — and the per-user records behind the queued paths must be inited once.

import {
  ComposerSolsticeActions,
  ComposerVaultActions,
} from '@1delta/calldata-sdk-sol'
import { fetchSolsticeVaults } from '@1delta/margin-fetcher-sol'

const ctx = { rpc, vaults: await fetchSolsticeVaults({ rpc }) }
const lock = await ComposerSolsticeActions.deposit(
  { vault: 'eUSX', account, amount: 1_000_000_000n },
  ctx,
)
const q = await ComposerSolsticeActions.simulate(
  { vault: 'JR-strcUSX', direction: 'deposit', amount: 1_000_000_000n },
  ctx,
) // the program's number
const req = await ComposerSolsticeActions.requestRedeem(
  { vault: 'SR-strcUSX', account, shares },
  ctx,
) // init + senior_unlock_queued
const now = await ComposerSolsticeActions.redeemInstant(
  { vault: 'SR-strcUSX', account, shares },
  ctx,
) // 10 bps
const usx = await ComposerSolsticeActions.claim(
  { vault: 'JR-strcUSX', account, batch: 'AUG-26-26' },
  ctx,
)
// or through the uniform surface:
await ComposerVaultActions.deposit(
  { provider: 'solstice', vault: 'eUSX', account, amount, decimals: 6 },
  { solstice: ctx },
)

solstice.live.test.ts simulates every one of them on mainnet as a borrowed program-owned identity — deposits agree with the ledger estimate to 1e-6, the exits land where the row says, and the paths that must fail fail on the program's own check.

Leverage — ComposerMargin

Every venue loops through its OWN stack (LOOPING.md): a flash pair (Jupiter Lend's flashloan program at 0 bps, Kamino's reserve pair, Save's) or a bracket (Project 0's start_flashloan … end_flashloan) around depositAndBorrow and a Jupiter swap, in one atomic list. The composer sizes from the caller's oracle price and the venues' fees (origination fees are grossed up — they come OUT of the borrowed amount), quotes the swap under the 64-lock budget, tries every flash candidate cheapest-first × two routes until the sealed message fits 1,232 bytes, and hands one SvmCallParams to assemble, which simulates it.

import {
  ComposerMargin,
  MarginTradeType,
  SvmTxUtilsLite,
} from '@1delta/calldata-sdk-sol'

const build = await ComposerMargin.createMarginFlashLoan(
  {
    account: wallet,
    marginData: {
      marginTradeType: MarginTradeType.Open,
      collateral: {
        lender: 'KAMINO_7u3He…',
        lenderAssetAddress: SOL_RESERVE,
        mint: WRAPPED_SOL,
        decimals: 9,
      },
      debt: {
        lender: 'KAMINO_7u3He…',
        lenderAssetAddress: USDC_RESERVE,
        mint: USDC,
        decimals: 6,
      },
    },
    input: { mint: WRAPPED_SOL, amount: 100_000_000n }, // 0.1 SOL
    targetLeverage: 2,
    slippageBps: 100,
    priceCollInDebtE18: usdcPerSolRawE18, // from the rows' oracle prices
    elevationGroup: 2, // Kamino: requested between the deposit and the borrow
  },
  { rpc, jupiterSwapApi, save: { rpc }, project0: { rpc, publicData } },
)
// build.meta: { flash: { provider, feeBps }, sizing: { side, flashAmount, … }, swap, lockBudget, route, bytes, accountKeys }
const { transactions } = await SvmTxUtilsLite.assemble(build, {
  fetchers,
  payer: wallet,
})

What the live gate found (test/margin.live.test.ts, mainnet simulation, 2026-09-20): a 2× SOL/USDC open fits one transaction on Jupiter Lend (vault 1), Kamino main (existing obligation), Save main and Project 0; a 3× JitoSOL/SOL open on Kamino requests elevation group 2 in the list. A Kamino loop on a wallet with no obligation is refused (KaminoObligationRequired — the hosted borrow builder needs it to exist; deposit first). A same-asset MIGRATE Kamino → Save measures 1,243 B — 11 over — and is refused with the measurement (TransactionTooLarge); a lookup table of ours for the pairs' keys is the lever. Loopscale loops are venue-built: LoopscaleLending.openLoop (or ComposerMargin.createLoopscaleLoop), /creditbook/flash_borrow with the wallet in a user-wallet header and cpiIxs[].data in base64 (the docs say base58; base58 is a 500).

Public RPCs 429 a full run of the live gate (each build reads the venue's accounts, quotes three flash providers and measures); set SVM_RPC_URLS or run the cases one at a time.

Not here

  • Exponent YT, liquidity, orderbook, post-maturity redeem — one more IDL instruction each, on the same method (EXPONENT.md §4).
  • The 1delta lookup tables themselves — flashloan/lut.ts plans them and pnpm flash-lut --keypair <file> --send creates them; until the addresses are in ONEDELTA_FLASH_LOOKUP_TABLES nothing compresses beyond the venues' own tables.
  • A plain spot swap — SOLANA_PLAN §5.1 relays Jupiter's sealed transaction; the instruction form here exists for composition.
  • Token-2022 detection — the ATA derivation needs the mint's program; pass jupiterLendParams.tokenProgram for a Token-2022 mint (PYUSD). The token list knows.