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

@whworjs7946/clmsr-v0

v1.13.0

Published

TypeScript SDK for CLMSR market calculations and utilities

Readme

CLMSR TypeScript SDK

📈 CLMSR (Conditional Liquidity Market Maker) TypeScript SDK for prediction market systems

🎯 Overview

TypeScript SDK for CLMSR (Constant Logarithmic Market Scoring Rule) prediction market calculations.

v1.11.0 adds overlay-fee awareness across all pricing helpers while keeping the underlying mathematics pure and deterministic.

🔄 What's new in v1.11.0

  • Overlay fee descriptors (e.g. {"policy":"percentage","params":{"bps":"50"}}) are now propagated through the SDK.
    • All buy/sell helpers return feeAmount, feeRate, and rich feeInfo.
    • Pure helpers in fees.ts allow frontends to preview on-chain fee policies without importing ABIs.
  • Flexible fee metadata: descriptors can embed labels such as "name": "PercentFeePolicy50bps", which the SDK surfaces to your UI.
  • Ethers v6 dependency: the SDK now bundles lightweight resolver helpers built on top of [email protected].

⚠️ TypeScript breaking change: the additional fields on OpenCostResult, IncreaseCostResult, DecreaseProceedsResult, and CloseProceedsResult are mandatory.
Update any local mocks or adapters that instantiate these interfaces before upgrading.

🔁 Prior release: v1.8.0 settlement enhancement

  • Previous: calculateClaim(position, settlementLowerTick, settlementUpperTick)
  • Enhanced: calculateClaim(position, settlementTick)

This change allows frontends to display the exact settlement price instead of just knowing a winning range, improving user experience and transparency.

🚀 Key Features

  • Pure functional calculations: TypeScript implementation of contract view functions
  • Fixed quantity limits: Corrected scaling for market-specific limits (α × 0.13 × 1000)
  • Large trade support: Proper handling of quantities up to 26,000 USDC (α=200) with accurate calculations
  • Enhanced error handling: Clear validation messages with correct limit display
  • Improved scaling: Consistent MathUtils-based decimal handling for all conversions
  • Optimized type system: Minimal required fields for better performance
  • Inverse function calculation: Mathematical inverse function to calculate quantity from target cost
  • High-precision arithmetic: Accurate fixed-point operations based on Big.js
  • LMSR compliant: Implements all LMSR mathematical properties
  • Comprehensive testing: 25+ test cases including large-scale trading scenarios

📦 Installation

npm install @whworjs7946/clmsr-v0

🏁 Quick Start

1. Basic Usage

import {
  CLMSRSDK,
  toWAD,
  toMicroUSDC,
  mapMarket,
  mapDistribution,
} from "@whworjs7946/clmsr-v0";

// SDK instance creation
const sdk = new CLMSRSDK();

// Market configuration (converted from raw data)
const rawMarket = {
  liquidityParameter: "1000000000000000000000", // 1000 * 1e18 (WAD)
  minTick: 100000, // $1000.00
  maxTick: 140000, // $1400.00
  tickSpacing: 100, // $1.00 increments
};
const market = mapMarket(rawMarket);

// Distribution data (raw data from GraphQL - unified scaling)
const rawDistribution = {
  totalSum: "400000000000000000000", // WAD format (18 decimals)
  minFactor: "1000000000000000000", // WAD format (18 decimals)
  maxFactor: "2000000000000000000", // WAD format (18 decimals)
  avgFactor: "1500000000000000000", // WAD format (18 decimals)
  totalVolume: "50000000", // raw USDC (6 decimals) - 50 USDC
  binFactors: ["1000000000000000000", "1500000000000000000" /* ... */], // WAD
  binVolumes: ["1000000", "2000000" /* ... */], // raw USDC (6 decimals)
  tickRanges: ["100000-100100", "100100-100200" /* ... */], // each = [tick, tick+spacing)
};
const distribution = mapDistribution(rawDistribution);

// Calculate cost for betting 50 USDC on [$1150-$1250] range
const result = sdk.calculateOpenCost(
  115000, // lowerTick ($1150.00)
  125000, // upperTick ($1250.00)
  toUSDC("50"), // 50 USDC
  distribution,
  market
);

console.log(`Cost: ${result.cost.toString()} USDC`);
console.log(`Average price: ${result.averagePrice.toString()}`);

2. Large Trade Support with Dynamic Limits

// Market-specific maximum quantity (α × 0.13 × 1000)
// For α = 200: max = 26,000 USDC
// For α = 1000: max = 130,000 USDC

// Large quantities within limits are handled safely
const largeResult = sdk.calculateOpenCost(
  115000,
  125000,
  toUSDC("25000"), // 25,000 USDC (within α=200 limit)
  distribution,
  market
); // ✅ Processes normally with automatic chunking

// Exceeding market limits throws clear error
try {
  sdk.calculateOpenCost(115000, 125000, toUSDC("30000"), distribution, market);
} catch (error) {
  console.log(error.message);
  // "Quantity too large. Max per trade = 26000 USDC (market limit: α × 0.13 × 1000)"
}

3. Inverse Function Calculation

// Calculate how much can be bet when willing to spend up to 300 USDC (total including fees)
const targetCost = toUSDC("300");
const inverseBuy = sdk.calculateQuantityFromCost(
  115000,
  125000,
  targetCost,
  distribution,
  market
);

console.log(`Buy quantity: ${inverseBuy.quantity.toString()}`);
console.log(
  `Actual base cost (excl. fee): ${inverseBuy.actualCost.toString()}`
);

// Calculate how much must be sold to receive 180 USDC after paying fees
const position = {
  lowerTick: 115000,
  upperTick: 125000,
  quantity: toUSDC("800"), // current position size
};

const targetProceeds = toUSDC("180");
const inverseSell = sdk.calculateQuantityFromProceeds(
  position,
  targetProceeds,
  distribution,
  market
);

console.log(`Sell quantity: ${inverseSell.quantity.toString()}`);
console.log(
  `Actual base proceeds (before fee): ${inverseSell.actualProceeds.toString()}`
);

4. Overlay fee helpers (pure functions)

import { FeePolicyKind } from "@whworjs7946/clmsr-v0";
import { CLMSRSDK } from "@whworjs7946/clmsr-v0";

// Descriptor published by on-chain fee policy contracts or the subgraph
const percentageDescriptor = JSON.stringify({
  policy: "percentage",
  params: {
    bps: "150", // 1.5%
    name: "OnePointFive",
  },
});

// Attach the descriptor to the market object (e.g. value fetched from the subgraph)
market.feePolicyDescriptor = percentageDescriptor;

const sdk = new CLMSRSDK();
const open = sdk.calculateOpenCost(
  115000,
  125000,
  toMicroUSDC("50"),
  distribution,
  market
);
if (open.feeInfo.policy === FeePolicyKind.Percentage) {
  console.log(
    open.feeAmount.toString(), // fee amount (micro USDC)
    open.feeRate.toString(), // decimal fee rate
    open.feeInfo.bps?.toString() // raw basis points (150)
  );
  const totalCostWithFee = open.cost.plus(open.feeAmount);
  console.log(totalCostWithFee.toString());
}

ℹ️ As long as you forward the descriptor string from the chain or subgraph, the SDK can resolve the fee calculation, display labels, and expose the raw basis points without any additional configuration. Keep the descriptor in sync with the latest on-chain value to guarantee accurate previews.

📖 API Reference

Data Types

Raw Types (Received from GraphQL/Subgraph)

interface MarketDistributionRaw {
  // Required fields for calculations
  totalSum: string; // WAD format (18 decimals) - "400000000000000000000"
  binFactors: string[]; // WAD format array - ["1000000000000000000", ...]

  // Optional fields (informational only)
  minFactor?: string; // WAD format (18 decimals) - "1000000000000000000"
  maxFactor?: string; // WAD format (18 decimals) - "2000000000000000000"
  avgFactor?: string; // WAD format (18 decimals) - "1500000000000000000"
  totalVolume?: string; // raw USDC (6 decimals) - "50000000"
  binVolumes?: string[]; // raw USDC array - ["1000000", "2000000", ...]
  tickRanges?: string[]; // tick range array - ["100000-100100", ...]
}

interface MarketRaw {
  liquidityParameter: string; // WAD format - "1000000000000000000000"
  minTick: number;
  maxTick: number;
  tickSpacing: number;
  feePolicyDescriptor?: string;
}

SDK Calculation Types (Big Objects)

interface MarketDistribution {
  // Required fields for calculations
  totalSum: WADAmount; // WAD calculation value (18 decimals) - core calculation
  binFactors: WADAmount[]; // WAD format bin factor array (18 decimals) - core calculation

  // Optional fields (informational only)
  minFactor?: WADAmount; // Minimum factor value (WAD, 18 decimals)
  maxFactor?: WADAmount; // Maximum factor value (WAD, 18 decimals)
  avgFactor?: WADAmount; // Average factor value (WAD, 18 decimals)
  totalVolume?: USDCAmount; // Total volume (raw 6 decimals) - informational
  binVolumes?: USDCAmount[]; // Bin volume array (raw 6 decimals) - informational
  tickRanges?: string[]; // Tick range string array
}

interface Market {
  liquidityParameter: WADAmount; // Big object (WAD)
  minTick: number;
  maxTick: number;
  tickSpacing: number;
  feePolicyDescriptor?: string;
}

Adapter Functions

mapDistribution()

function mapDistribution(raw: MarketDistributionRaw): MarketDistribution;

// Usage example
const dist = mapDistribution(await fetchFromGraphQL(marketId));

mapMarket()

function mapMarket(raw: MarketRaw): Market;

// Usage example
const market = mapMarket(await fetchMarketFromGraphQL(marketId));

Core Calculation Functions

calculateOpenCost()

Calculate cost to open new position

calculateOpenCost(
  lowerTick: number,
  upperTick: number,
  quantity: USDCAmount,
  distribution: MarketDistribution,
  market: Market
): OpenCostResult

calculateDecreaseProceeds() / calculateSellProceeds()

Calculate proceeds when decreasing position (both functions use unified internal logic)

calculateDecreaseProceeds(
  position: Position,
  sellQuantity: USDCAmount,
  distribution: MarketDistribution,
  market: Market
): DecreaseProceedsResult

calculateSellProceeds(
  position: Position,
  sellQuantity: USDCAmount,
  distribution: MarketDistribution,
  market: Market
): DecreaseProceedsResult

calculateQuantityFromCost()

Calculate quantity from target cost (inverse function)

calculateQuantityFromCost(
  lowerTick: number,
  upperTick: number,
  targetCost: USDCAmount,
  distribution: MarketDistribution,
  market: Market,
  includeFees?: boolean
): QuantityFromCostResult
  • targetCost is the total spending limit including fees.
  • includeFees set to false calculates based on pure cost excluding fees (default true).
  • The returned actualCost is the pure betting cost (excluding fees), and calling calculateOpenCost with quantity should result in actualCost + feeAmount being close to targetCost within the same range.

calculateQuantityFromProceeds()

Calculate sell quantity from target proceeds (inverse function)

calculateQuantityFromProceeds(
  position: Position,
  targetProceeds: USDCAmount,
  distribution: MarketDistribution,
  market: Market,
  includeFees?: boolean
): QuantityFromProceedsResult
  • targetProceeds is the actual amount you want to receive after fees.
  • includeFees set to false calculates based on base proceeds excluding fees (default true).
  • The returned actualProceeds is the pre-fee base proceeds, and calling calculateDecreaseProceeds with the same quantity should result in actualProceeds - feeAmount being close to targetProceeds.

calculateClaim()

Calculate claim amount after settlement

calculateClaim(
  position: Position,
  settlementTick: number
): ClaimResult

Utility Functions

Scale Conversion

toWAD(amount: string | number): WADAmount    // Convert to 18 decimal WAD
toUSDC(amount: string | number): USDCAmount  // Convert to 6 decimal USDC

🏗️ Architecture

Unified Scaling Design

┌─────────────────┐    ┌──────────────┐    ┌─────────────┐
│  Subgraph API   │───▶│   Adapter    │───▶│ SDK Calc    │
│ (BigInt→string) │    │ (parse only) │    │ (Big ops)   │
└─────────────────┘    └──────────────┘    └─────────────┘
   Raw WAD/USDC          mapXXX()           raw scale
  • Subgraph Layer: Provides raw-scale BigInt values converted to strings
  • Adapter Layer: Simple string → Big object conversion (no scaling)
  • SDK Layer: Performs calculations using raw contract scales

Scaling Standards

  • Factors: WAD format (18 decimals) - used for LMSR calculations
  • USDC Amounts: Raw 6 decimals - quantity, cost, proceeds
  • No normalization: All values maintain contract-native scales

Chunking Support

// Internal safeExp use makes large values safe
// Auto chunk splitting when quantity/α > 0.13
const result = sdk.calculateOpenCost(
  lowerTick,
  upperTick,
  toUSDC("10000"), // very large quantity
  distribution,
  market
); // ✅ Processes normally

🧪 Testing

npm test

25+ test cases including:

  • ✅ Price impact (non-linearity)
  • ✅ Range effects
  • ✅ Mathematical consistency (pure functions)
  • ✅ Inverse function accuracy
  • ✅ Claim logic
  • ✅ Error handling
  • ✅ Large-scale trading (α=200 environment)
  • ✅ Dynamic quantity limits
  • ✅ Scaling & Chunking

📋 Type Definitions

type WADAmount = Big; // 18 decimal (factor values)
type USDCAmount = Big; // 6 decimal (quantity/cost values)
type Quantity = Big; // 6 decimal
type Tick = number; // tick value

interface Position {
  lowerTick: Tick;
  upperTick: Tick;
  quantity: Quantity;
}

📝 Changelog

v1.6.2 (Latest)

  • 🔧 Error handling consistency: Unified error types across SDK (ValidationError, CalculationError)
  • 📊 Enhanced MathUtils integration: Consistent use of MathUtils functions for all scaling operations
  • 🎯 Refined decimal precision: Improved Big.js usage for consistent decimal handling
  • ⚡ Code consistency improvements: Eliminated magic numbers, standardized conversion patterns

v1.6.1

  • 🔢 Fixed decimal scaling: Corrected quantity limits and scaling issues
  • 📈 Enhanced quantity limits: Proper market-specific limit calculations (α × 0.13 × 1000)
  • 🛠️ Improved error messages: Clear validation messages with accurate limit display

🔗 Related Links