agentsclimarketplace

Cdpm calculation skill

Skill RandyPen/cdpm/skills/cdpm-calculation-skill

Install
npx -y skills add RandyPen/cdpm --skill cdpm-calculation-skill

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

CDPM calculation utilities using Cetus DLMM SDK plus the Scallop and Kai SAV lending math used by scallop_supply / scallop_redeem / kai_supply / kai_redeem. Provides liquidity calculation, bin price math, position management, fee calculations, and yield-fee accounting for both lending integrations. Use when performing mathematical operations for CDPM positions.

SKILL.md

8.7 KB, ~2.3k tokens by cl100k_base, as published. Nobody here has run it

CDPM Calculation Guide

Overview

This skill provides calculation utilities for CDPM (Cetus DLMM Position Manager) using the Cetus DLMM SDK, plus off-chain twins of both lending integrations' upstream math — Scallop (scallop_*) and Kai SAV (kai_*). All Cetus calculations should use the SDK for accuracy and to handle edge cases properly; the Scallop and Kai formulas mirror the upstream protocol::mint / protocol::redeem and kai_vault::deposit / kai_vault::withdraw math that cdpm composes into single-call entries. The two integrations share pm.lending: Bag, the same fee_house.fee_rate knob, and the same principal-amortization shape — only the predictors differ (Scallop reads balance_sheet, Kai reads total_available_balance + total_yt_supply).

Installation

npm install @cetusprotocol/dlmm-sdk

SDK Imports

import { BinUtils, FeeUtils } from '@cetusprotocol/dlmm-sdk/utils'

Topics

Core Calculations

Lending Math (Scallop & Kai SAV)

  • Scallop Lending MathpredictScallopMint / predictScallopRedeem, principal amortization, yield-fee deduction, redemption sizing (inverse formulas + worked example), live supply APY via @scallop-io/sui-scallop-sdk, Scallop-vs-Kai picker.
  • Kai SAV Lending MathpredictKaiDeposit / predictKaiWithdraw for <T, YT> vaults; live APY via @kunalabs-io/kai.
  • Cross-Protocol PTB (cdpm + Scallop + Kai) — Mysten-rooted shared-Transaction pattern, approach comparison table, atomic Scallop ↔ Kai rebalance, dust-prediction patterns when composing redeem → add-liquidity.

Advanced Topics

Reference


Complete Examples

Example 1: Create Position Calculation

import { BinUtils } from '@cetusprotocol/dlmm-sdk/utils'

async function calculatePosition(
  poolInfo: { bin_step: number; active_bin_id: number },
  tokenADecimals: number,
  tokenBDecimals: number,
  depositA: string,
  depositB: string,
  slippagePercent: number
) {
  const { bin_step, active_bin_id } = poolInfo
  
  // 1. Get current price
  const currentPrice = BinUtils.getPriceFromBinId(
    active_bin_id,
    bin_step,
    tokenADecimals,
    tokenBDecimals
  )
  
  // 2. Calculate price range with slippage
  const minPrice = (parseFloat(currentPrice) * (1 - slippagePercent / 100)).toString()
  const maxPrice = (parseFloat(currentPrice) * (1 + slippagePercent / 100)).toString()
  
  // 3. Get bin IDs
  const lowerBinId = BinUtils.getBinIdFromPrice(
    minPrice, bin_step, true, tokenADecimals, tokenBDecimals
  )
  const upperBinId = BinUtils.getBinIdFromPrice(
    maxPrice, bin_step, false, tokenADecimals, tokenBDecimals
  )
  
  // 4. Calculate position count
  const positionCount = BinUtils.getPositionCount(lowerBinId, upperBinId)
  
  // 5. Distribute liquidity
  const binCount = upperBinId - lowerBinId + 1
  const amountAPerBin = (BigInt(depositA) / BigInt(binCount)).toString()
  const amountBPerBin = (BigInt(depositB) / BigInt(binCount)).toString()
  
  // 6. Calculate total liquidity
  const activeQPrice = BinUtils.getQPriceFromId(active_bin_id, bin_step)
  const totalLiquidity = BinUtils.getLiquidity(depositA, depositB, activeQPrice)
  
  return {
    lowerBinId,
    upperBinId,
    positionCount,
    totalLiquidity,
    bins: Array.from({ length: binCount }, (_, i) => ({
      binId: lowerBinId + i,
      amountA: amountAPerBin,
      amountB: amountBPerBin
    }))
  }
}

Example 2: Remove Liquidity Calculation

function calculateRemoval(
  positionBins: Array<{
    binId: number
    amountA: string
    amountB: string
    liquidity: string
  }>,
  percentage: number  // 0-100
): Array<{ binId: number; amountA: string; amountB: string }> {
  const results = []
  
  for (const bin of positionBins) {
    const removeLiquidity = (BigInt(bin.liquidity) * BigInt(percentage) / 100n).toString()
    
    const { amount_a, amount_b } = BinUtils.calculateOutByShare(
      { amount_a: bin.amountA, amount_b: bin.amountB, liquidity: bin.liquidity },
      removeLiquidity
    )
    
    results.push({
      binId: bin.binId,
      amountA: amount_a,
      amountB: amount_b
    })
  }
  
  return results
}

Example 3: Rebalancing Calculation

async function calculateRebalance(
  currentBins: Array<{ binId: number; liquidity: string }>,
  targetActiveBinId: number,
  rangeWidth: number,
  binStep: number
) {
  const lowerBinId = targetActiveBinId - rangeWidth
  const upperBinId = targetActiveBinId + rangeWidth
  
  // 1. Calculate total liquidity
  let totalLiquidity = 0n
  for (const bin of currentBins) {
    totalLiquidity += BigInt(bin.liquidity)
  }
  
  // 2. Calculate new distribution
  const targetBinCount = rangeWidth * 2 + 1
  const liquidityPerBin = (totalLiquidity / BigInt(targetBinCount)).toString()
  
  // 3. Get amounts needed for each bin
  const targetBins = []
  for (let i = 0; i < targetBinCount; i++) {
    const binId = lowerBinId + i
    const qPrice = BinUtils.getQPriceFromId(binId, binStep)
    
    // For equal distribution, amounts depend on price
    // amount_a = liquidity / (2 * price), amount_b = liquidity / 2
    const amountA = (BigInt(liquidityPerBin) / (2n * BigInt(qPrice) >> 64n)).toString()
    const amountB = (BigInt(liquidityPerBin) / 2n).toString()
    
    targetBins.push({ binId, amountA, amountB, liquidity: liquidityPerBin })
  }
  
  // 4. Calculate positions needed
  const positionCount = BinUtils.getPositionCount(lowerBinId, upperBinId)
  
  return { targetBins, positionCount }
}

Best Practices

1. Always Use SDK Utils

// Good - Use SDK
import { BinUtils } from '@cetusprotocol/dlmm-sdk/utils'
const liquidity = BinUtils.getLiquidity(amountA, amountB, qPrice)

// Bad - Manual calculation
const liquidity = (BigInt(price) * BigInt(amountA)) + (BigInt(amountB) << 64n)

2. Pass Amounts as Strings

// Good - String format
const liquidity = BinUtils.getLiquidity('1000000', '1200000', qPrice)

// Bad - Number format (precision loss)
const liquidity = BinUtils.getLiquidity(1000000, 1200000, qPrice)

3. Cache QPrice

// Good - Cache QPrice
const qPriceCache = new Map()
function getCachedQPrice(binId: number, binStep: number) {
  const key = `${binId}-${binStep}`
  if (!qPriceCache.has(key)) {
    qPriceCache.set(key, BinUtils.getQPriceFromId(binId, binStep))
  }
  return qPriceCache.get(key)
}

4. Validate Inputs

function validateBinRange(lowerBinId: number, upperBinId: number) {
  if (lowerBinId >= upperBinId) {
    throw new Error('Invalid range: lower must be less than upper')
  }
  if (upperBinId - lowerBinId > 1000) {
    throw new Error('Range too large: max 1000 bins')
  }
}

5. Handle Errors

try {
  const binId = BinUtils.getBinIdFromPrice(price, binStep, true, decimalsA, decimalsB)
} catch (error) {
  console.error('Failed to calculate bin ID:', error)
  // Fallback or retry logic
}

Related Skills

  • cdpm-user-sdk - User operations guide
  • cdpm-agent-sdk - Agent automation strategies
  • cdpm-protocol-sdk - Protocol integration guide
  • cetus-dlmm-sdk-skill - Full Cetus DLMM SDK documentation

What ships with it: 13 files

142.8 KB alongside SKILL.md

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.