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

@lit-protocol/flows-clmm

v0.2.0

Published

Pure concentrated-liquidity math, calldata codecs, validators, and pricing helpers for Flows contract-call actions.

Readme

@lit-protocol/flows-clmm

Pure concentrated-liquidity math, calldata codecs, fail-closed validators, and USD pricing helpers for Flows contract-call actions (Uniswap v3 and Aerodrome/Velodrome Slipstream).

This is the package the certified onchain-call executor imports inside the TEE to classify, validate, and price CL call plans — the same code runs host-side for dry-runs, so what your proposer computes locally is byte-for-byte what the seat enforces.

npm install @lit-protocol/flows-clmm

ESM only, Node ≥ 20, zero runtime dependencies.

Conventions (read first)

  • Amounts and liquidity are raw base units (no decimal scaling), accepted as string | bigint, returned as decimal strings — never JS numbers.
  • Human prices are decimal strings (e.g. '2543.21'), parsed/emitted with 18 fractional digits of precision internally. sqrtPriceX96 values are Q64.96 fixed-point (bigint or decimal string).
  • Ticks are plain integers in [-887272, 887272], snapped to tickSpacing. Ranges are upper-exclusive (tickLower <= tick < tickUpper).
  • Profiles: 'univ3' keys pools by fee (uint24, e.g. 500); 'slipstream' keys pools by tickSpacing (int24, e.g. 100). Calldata layouts differ — the codec handles both.
  • Addresses are lowercased 0x…40-hex strings in all decoded output.
  • Everything fails closed: unrecognized calldata classifies to null, validators return violations instead of guessing, pricing throws or returns null rather than mis-pricing.

Math (sqrtRatioAtTick, ranges, amounts)

| Export | Signature | Notes | |---|---|---| | sqrtRatioAtTick | (tick: number) => bigint | Uniswap-v3 TickMath port; sqrtPriceX96 at tick. Throws outside the tick domain. | | tickToPrice | (tick, dec0, dec1) => string | Human price of token0 denominated in token1 (token1-per-token0), decimals-adjusted. | | priceToTick | (price: string, tickSpacing, dec0, dec1) => number | Inverse of tickToPrice; binary-search then snap to tickSpacing. | | nearestUsableTick | (tick, tickSpacing) => number | Round to the nearest spacing multiple, clamped to the usable range. | | centeredRange | (currentTick, widthTicks, tickSpacing) => { tickLower, tickUpper } | Build a ~widthTicks-wide range centered on currentTick. | | isInRange | (currentTick, tickLower, tickUpper) => boolean | Upper-exclusive, Uniswap convention. | | getAmountsForLiquidity | (sqrtPriceX96, tickLower, tickUpper, liquidity) => { amount0, amount1 } | Raw token amounts a liquidity figure represents at the current price. | | getLiquidityForAmounts | (sqrtPriceX96, tickLower, tickUpper, amount0, amount1) => string | Max liquidity mintable from raw amounts. |

Codec (encodeCall / classifyCall)

type ClmmProfile = 'univ3' | 'slipstream';
type TargetRole = 'positionManager' | 'gauge' | 'erc20' | 'erc721' | 'pool' | 'router';
type CallShape =
  | 'mint' | 'increaseLiquidity' | 'decreaseLiquidity' | 'collect' | 'burn'
  | 'erc20Approve' | 'erc721Approve' | 'erc721SafeTransferFrom'
  | 'gaugeDeposit' | 'gaugeWithdraw' | 'gaugeGetReward' | 'exactInputSingle';
  • encodeCall(profile, shape, args) => { to, data, value } — encode a CL / position-manager / router / gauge / ERC call. Slipstream mints key by int24 tickSpacing and append sqrtPriceX96; univ3 mints key by uint24 fee. Guards reject invalid addresses, out-of-range ints, and refuse MaxUint256 ERC-20 approvals outright. Args are shape-dependent and named exactly like the ABI fields (amount0Desired, amountOutMinimum, …).
  • classifyCall(profile, to, dataHex, { role }) => ClassifiedCall | null — the fail-closed decoder. The role picks the decoder (ERC-20 and ERC-721 approve share a selector), and only static-layout calls decode; a router role accepts only the profile's exactInputSingle. Anything else → null.
  • ClassifiedCall is a discriminated union on kind (one variant per CallShape) carrying the decoded fields — amounts as decimal strings, ticks as numbers, addresses lowercased, plus the 10-char selector.
  • SELECTORS — the pinned 4-byte selector table (e.g. univ3Mint: 0x88316456, slipstreamMint: 0xb5007d1f, slipstreamExactInputSingle: 0xa026383e).

Validation (validateLpPlan)

validateLpPlan(plan: LpPlan, intent: LpIntent, constraints: LpConstraints, poolState: LpPoolState)
  => { ok: boolean; violations: string[]; classified: ClassifiedCall[] }

Fail-closed policy validator for a whole call plan: classifies every tx and enforces target/selector allowlists, no native value, recipient == pkpAddress, deadline bounds, slippage floors (amountMin / amountOutMinimum vs desired / expectedAmountOut), pinned pool tuples, range width and center-vs-TWAP bounds, bounded ERC-20 approvals (spender == main target, amount ≤ decoded need), ERC-721 approval to the gauge only, and tokenId consistency. See the exported LpPlan, LpIntent, LpConstraints, LpPoolState interfaces for the exact field set.

Pricing (TWAP guards + USD notional)

| Export | Signature | Notes | |---|---|---| | twapTick | (observations: { tickCumulative, secondsAgo }[], windowSec) => number | Time-weighted average tick from ≥2 observe() points. | | spotVsTwapDeviationBps | (slot0Tick, twap) => number | Deviation in basis points, computed in tick space (scale-invariant), ceiling-rounded so a guard can only refuse earlier. | | poolSpotUsd | (poolState, quoteSide, quoteDecimals, quoteSideUsd = '1') => string | USD spot price of the non-quote token. | | positionValueUsd | (position, poolState, quoteSide, quoteSideUsd = '1') => string | USD value of both legs of an LP position. | | classifiedCallNotionalUsd | (call, poolState, quoteSide, swapTokenInSide?, quoteSideUsd = '1') => string \| null | USD notional of a classified call: mint/increase price the desired amounts, decreaseLiquidity the minima, collect/gaugeGetReward'0', swaps price amountIn (and require swapTokenInSide), everything else → null. |

quoteSide ('token0' | 'token1', named stableSide in the signatures for compatibility) is the pool side with a known USD price, and quoteSideUsd is that price as a decimal string — '1' for an allowlisted stable (the classic rule), or a derived price to route pools with no stable side: price WETH from its own WETH/USDC reference pool, then pass quoteSideUsd = <wethUsd> to price a LITKEY/WETH pool. PricingPoolState is { sqrtPriceX96, tick, token0Decimals, token1Decimals }.

Example: Slipstream mint → decrease → collect

import {
  centeredRange, encodeCall, getLiquidityForAmounts, nearestUsableTick,
} from '@lit-protocol/flows-clmm';

const NPM = '0x827922686190790b37229fd06084350e74485b72'; // Aerodrome Slipstream NPM (Base)
const WETH = '0x4200000000000000000000000000000000000006';
const LITKEY = '0xf732a566121fa6362e9e0fbdd6d66e5c8c925e49';
const PKP = '0xYourFlowsWallet';
const TICK_SPACING = 200;
const deadline = Math.floor(Date.now() / 1000) + 900;

// 1. Range around the current tick (read slot0/observe on-chain yourself).
const { tickLower, tickUpper } = centeredRange(currentTick, 4000, TICK_SPACING);

// 2. Bounded approvals + mint. Token order must be the pool's sorted order.
const callPlan = [
  encodeCall('slipstream', 'erc20Approve', { to: WETH, spender: NPM, amount: wethAmount }),
  encodeCall('slipstream', 'erc20Approve', { to: LITKEY, spender: NPM, amount: litkeyAmount }),
  encodeCall('slipstream', 'mint', {
    to: NPM, token0: WETH, token1: LITKEY, tickSpacing: TICK_SPACING,
    tickLower, tickUpper,
    amount0Desired: wethAmount, amount1Desired: litkeyAmount,
    amount0Min: wethMin, amount1Min: litkeyMin, // desired × (10000 − slippageBps) / 10000
    recipient: PKP, deadline, sqrtPriceX96: 0,
  }),
];

// 3. Later: atomic exit — decrease binds the intent, collect rides as follower.
const exitPlan = [
  encodeCall('slipstream', 'decreaseLiquidity', {
    to: NPM, tokenId, liquidity, amount0Min, amount1Min, deadline,
  }),
  encodeCall('slipstream', 'collect', {
    to: NPM, tokenId, recipient: PKP,
    amount0Max: '340282366920938463463374607431768211455', // MaxUint128
    amount1Max: '340282366920938463463374607431768211455',
  }),
];

Each { to, data, value } goes into a Flows contract-call proposal's callPlan; the certified executor re-classifies, re-validates, re-prices, and re-judges the plan in-TEE before signing. See the Flows docs (verb-reference.md, manifest-reference.md, and the custom DeFi tutorial) for the manifest/policy side.