> For the complete documentation index, see [llms.txt](https://docs.ferra.ag/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ferra.ag/integration/dlmm/typescript-sdk/utilities-and-reference/best-practices.md).

# Best Practices

Performance optimization tips for efficient DLMM interactions. Minimize gas usage, batch operations effectively, and implement robust patterns for production applications.

### Gas Optimization

#### Batch Operations

```typescript
// ❌ Bad: Multiple transactions
await sdk.Pair.removeLiquidity(pair, { positionId, binIds: [1] });
await sdk.Pair.removeLiquidity(pair, { positionId, binIds: [2] });
await sdk.Pair.removeLiquidity(pair, { positionId, binIds: [3] });

// ✅ Good: Single transaction
await sdk.Pair.removeLiquidity(pair, { 
  positionId, 
  binIds: [1, 2, 3] 
});
```

#### Minimize Bin Count

```typescript
// Gas scales with number of bins
const gasEfficient = {
  // ❌ Excessive: 100 bins
  wide: Array.from({length: 101}, (_, i) => i - 50),
  
  // ✅ Efficient: Focused liquidity
  focused: Array.from({length: 21}, (_, i) => i - 10)
};

// Consider gas cost vs capital efficiency
function optimizeBinCount(expectedVolatility: number): number {
  if (expectedVolatility < 0.01) return 10;  // Stable
  if (expectedVolatility < 0.05) return 20;  // Normal
  return 30; // Volatile
}
```

### Efficient Data Fetching

#### Cache Pair Data

```typescript
class PairCache {
  private cache = new Map<string, { data: LBPair, timestamp: number }>();
  private ttl = 60000; // 1 minute
  
  async getPair(pairAddress: string): Promise<LBPair> {
    const cached = this.cache.get(pairAddress);
    
    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.data;
    }
    
    const pair = await sdk.Pair.getPair(pairAddress);
    if (pair) {
      this.cache.set(pairAddress, { data: pair, timestamp: Date.now() });
    }
    
    return pair;
  }
}
```

#### Batch RPC Calls

```typescript
// ❌ Bad: Sequential calls
const pairs = [];
for (const address of pairAddresses) {
  const pair = await sdk.Pair.getPair(address);
  pairs.push(pair);
}

// ✅ Good: Parallel calls
const pairs = await Promise.all(
  pairAddresses.map(address => sdk.Pair.getPair(address))
);
```

#### Selective Data Loading

```typescript
// Only fetch what you need
async function getPositionSummary(positionId: string) {
  // Don't fetch full bin details if only need count
  const position = await sdk.Position.getLbPosition(positionId);
  
  // Lazy load expensive data
  let bins = null;
  const getBins = async () => {
    if (!bins) {
      const pair = await sdk.Pair.getPair(position.pair_id);
      bins = await sdk.Position.getPositionBins(pair, positionId);
    }
    return bins;
  };
  
  return { position, getBins };
}
```

### Smart Contract Interactions

#### Reuse Transactions

```typescript
// Build transaction once, execute multiple times
const buildAddLiquidityTx = (params: AddLiquidityParams) => {
  const tx = new Transaction();
  // ... build transaction
  return tx;
};

// Reuse for similar operations
const template = buildAddLiquidityTx(baseParams);
```

#### Optimize Call Data

```typescript
// Minimize distribution arrays
function compressDistribution(
  distribution: number[]
): { indices: number[], values: number[] } {
  const indices = [];
  const values = [];
  
  distribution.forEach((value, index) => {
    if (value > 0) {
      indices.push(index);
      values.push(value);
    }
  });
  
  return { indices, values };
}
```

### Error Handling Patterns

#### Retry with Backoff

```typescript
async function retryWithBackoff<T>(
  fn: () => Promise<T>,
  maxRetries: number = 3
): Promise<T> {
  let lastError;
  
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error;
      
      // Exponential backoff
      const delay = Math.min(1000 * Math.pow(2, i), 10000);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
  
  throw lastError;
}
```

#### Circuit Breaker

```typescript
class CircuitBreaker {
  private failures = 0;
  private lastFailTime = 0;
  private threshold = 5;
  private timeout = 60000; // 1 minute
  
  async execute<T>(fn: () => Promise<T>): Promise<T> {
    if (this.isOpen()) {
      throw new Error("Circuit breaker is open");
    }
    
    try {
      const result = await fn();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }
  
  private isOpen(): boolean {
    return this.failures >= this.threshold && 
           Date.now() - this.lastFailTime < this.timeout;
  }
  
  private onSuccess() {
    this.failures = 0;
  }
  
  private onFailure() {
    this.failures++;
    this.lastFailTime = Date.now();
  }
}
```

### Memory Management

#### Clean Up Large Objects

```typescript
// Release memory after use
async function processLargeDataset(pair: LBPair) {
  let reserves = await sdk.Pair.getPairReserves(pair);
  
  // Process data
  const result = processReserves(reserves);
  
  // Clear reference
  reserves = null;
  
  return result;
}
```

#### Stream Large Results

```typescript
// Process in chunks for large datasets
async function* streamPositionBins(
  pair: LBPair,
  positionId: string,
  chunkSize: number = 50
) {
  const bins = await sdk.Position.getPositionBins(pair, positionId);
  
  for (let i = 0; i < bins.length; i += chunkSize) {
    yield bins.slice(i, i + chunkSize);
  }
}

// Usage
for await (const chunk of streamPositionBins(pair, positionId)) {
  processChunk(chunk);
}
```

### Production Checklist

#### Pre-deployment

```typescript
const productionChecks = {
  // 1. Input validation
  validateInputs: (params: any) => {
    if (!params.amount || params.amount <= 0n) {
      throw new Error("Invalid amount");
    }
  },
  
  // 2. Network check
  ensureMainnet: () => {
    if (sdk.network !== "mainnet") {
      throw new Error("Not on mainnet");
    }
  },
  
  // 3. Gas buffer
  addGasBuffer: (estimatedGas: bigint) => {
    return (estimatedGas * 120n) / 100n; // 20% buffer
  },
  
  // 4. Slippage protection
  defaultSlippage: 0.5, // 0.5%
  maxSlippage: 5.0     // 5%
};
```

### Performance Monitoring

```typescript
// Track operation performance
class PerformanceMonitor {
  private metrics = new Map<string, number[]>();
  
  async measure<T>(
    name: string,
    fn: () => Promise<T>
  ): Promise<T> {
    const start = performance.now();
    
    try {
      return await fn();
    } finally {
      const duration = performance.now() - start;
      
      if (!this.metrics.has(name)) {
        this.metrics.set(name, []);
      }
      
      this.metrics.get(name)!.push(duration);
      
      // Log slow operations
      if (duration > 5000) {
        console.warn(`Slow operation: ${name} took ${duration}ms`);
      }
    }
  }
  
  getStats(name: string) {
    const times = this.metrics.get(name) || [];
    return {
      avg: times.reduce((a, b) => a + b, 0) / times.length,
      min: Math.min(...times),
      max: Math.max(...times)
    };
  }
}
```

### Key Principles

1. **Batch when possible** - Reduce transaction count
2. **Cache frequently used data** - Minimize RPC calls
3. **Validate early** - Fail fast with clear errors
4. **Handle errors gracefully** - Implement retries
5. **Monitor performance** - Track and optimize
6. **Use appropriate data structures** - Maps for lookups
7. **Clean up resources** - Prevent memory leaks
