Collect Fees

Understanding fee collection in DLMM - fees are automatically included when removing liquidity, with no separate claim mechanism required.

How DLMM Handles Fees

Unlike some protocols, DLMM:

  • No separate claim: Fees included in withdrawals

  • Auto-compound: Fees increase bin reserves

  • Proportional distribution: Based on liquidity share

  • Gas efficient: No extra transactions needed

Fees Are Included Automatically

// When you remove liquidity, fees are included
const tx = await sdk.Pair.removeLiquidity(pair, {
  positionId,
  binIds: selectedBins
});

// The returned tokens include:
// 1. Your share of reserves
// 2. Your share of accumulated fees
// No separate fee claim needed!

Understanding Fee Distribution

// Fees are part of bin reserves
interface BinReserves {
  reserve_x: bigint;    // Original liquidity
  reserve_y: bigint;    // Original liquidity
  fee_x: bigint;        // Accumulated fees
  fee_y: bigint;        // Accumulated fees
}

// When removing, you get proportional share of both
const totalX = reserve_x + fee_x;  // Your withdrawal includes both
const totalY = reserve_y + fee_y;

Compound Fees Strategy

Since fees auto-compound, you can:

// Option 1: Leave fees to compound
// Fees automatically increase your position value
// No action needed - most gas efficient

// Option 2: Remove and re-add to "collect"
async function compoundFees(
  pair: LBPair,
  positionId: string
) {
  // Step 1: Remove all liquidity (includes fees)
  const bins = await sdk.Position.getPositionBins(pair, positionId);
  const removal = await sdk.Pair.removeLiquidity(pair, {
    positionId,
    binIds: bins.map(b => b.id)
  });
  
  // Step 2: Re-add with new distribution if desired
  // This effectively "collects" and reinvests fees
}

Calculate Claimable Fees

// Preview fees included in withdrawal
async function previewFeesInWithdrawal(
  pair: LBPair,
  positionId: string,
  binIds: number[]
) {
  const amounts = await sdk.Position.getPositionBinsAmount(pair, positionId);
  
  // Filter to selected bins
  const selectedBins = amounts.filter(a => binIds.includes(a.id));
  
  // These amounts already include fees
  const totals = selectedBins.reduce((sum, bin) => ({
    totalWithFeesX: sum.totalWithFeesX + bin.amountX,
    totalWithFeesY: sum.totalWithFeesY + bin.amountY
  }), { totalWithFeesX: 0n, totalWithFeesY: 0n });
  
  return totals;
}

Partial Fee Collection

// Remove from high-fee bins only
async function collectFromProfitableBins(
  pair: LBPair,
  positionId: string
) {
  const reserves = await sdk.Pair.getPairReserves(pair);
  const positionBins = await sdk.Position.getPositionBins(pair, positionId);
  
  // Find bins with high fee ratios
  const profitableBins = positionBins.filter(pBin => {
    const reserve = reserves.find(r => r.id === pBin.id);
    if (!reserve) return false;
    
    const feeRatio = (reserve.fee_x + reserve.fee_y) / 
                    (reserve.reserve_x + reserve.reserve_y);
    return feeRatio > FEE_THRESHOLD;
  });
  
  // Remove from these bins to "collect" fees
  if (profitableBins.length > 0) {
    await sdk.Pair.removeLiquidity(pair, {
      positionId,
      binIds: profitableBins.map(b => b.id)
    });
  }
}

Why No Separate Collection?

DLMM's design benefits:

  1. Gas Efficiency: One less transaction type

  2. Simplicity: Fees always included

  3. Auto-Compounding: Fees earn more fees

  4. Fair Distribution: Proportional to contribution

Common Patterns

Monitor Fee Growth

// Track fee accumulation over time
async function trackFeeGrowth(
  pair: LBPair,
  positionId: string
) {
  const initial = await sdk.Position.getPositionBinsAmount(pair, positionId);
  
  // Check periodically
  setInterval(async () => {
    const current = await sdk.Position.getPositionBinsAmount(pair, positionId);
    
    const growth = {
      x: current.reduce((s, b) => s + b.amountX, 0n) - 
         initial.reduce((s, b) => s + b.amountX, 0n),
      y: current.reduce((s, b) => s + b.amountY, 0n) - 
         initial.reduce((s, b) => s + b.amountY, 0n)
    };
    
    console.log("Fee growth:", growth);
  }, 3600000); // Hourly
}

Exit Strategy

// Full exit includes all fees
const tx = await sdk.Pair.removeAndClosePosition(pair, positionId);
// All reserves + fees sent to wallet

Key Takeaways

  • No claim button: Fees included in removals

  • Always earning: Fees compound automatically

  • Flexible collection: Remove any bins anytime

  • Gas efficient: No separate transactions

Last updated