Skip to main content

Client Initialization

Use Environment Variables

Keep configuration out of source code:
import { KaleidoClient } from 'kaleidoswap-sdk';

const client = KaleidoClient.create({
  baseUrl: process.env.KALEIDO_API_URL!,
  nodeUrl: process.env.KALEIDO_NODE_URL,
  apiKey: process.env.KALEIDO_API_KEY,
});

Use a Singleton Client

Create one client instance and reuse it throughout your application:
// lib/kaleido.ts
import { KaleidoClient } from 'kaleidoswap-sdk';

let client: KaleidoClient | null = null;

export function getClient(): KaleidoClient {
  if (!client) {
    client = KaleidoClient.create({
      baseUrl: process.env.KALEIDO_API_URL!,
    });
  }
  return client;
}

Error Handling

Always Handle Errors

Wrap SDK calls in try/catch blocks and handle specific error types:
import { KaleidoError, NetworkError, QuoteExpiredError } from 'kaleidoswap-sdk';

try {
  const quote = await client.maker.getQuote({ /* ... */ });
} catch (error) {
  if (error instanceof QuoteExpiredError) {
    // Retry with a fresh quote
  } else if (error instanceof NetworkError && error.isRetryable()) {
    // Retry after a delay
  } else if (error instanceof KaleidoError) {
    // Log and handle gracefully
    console.error(`[${error.code}] ${error.message}`);
  }
}

Check Retryability

Use isRetryable() before implementing retry logic:
if (error instanceof KaleidoError && error.isRetryable()) {
  // Safe to retry: NetworkError, TimeoutError, 5xx errors, 429
}

Async Patterns

TypeScript: Parallel Requests

Use Promise.all for independent requests:
const [assets, pairs, lspInfo] = await Promise.all([
  client.maker.listAssets(),
  client.maker.listPairs(),
  client.maker.getLspInfo(),
]);
Use Promise.allSettled when you want partial results:
const results = await Promise.allSettled([
  client.maker.listAssets(),
  client.maker.listPairs(),
]);

for (const result of results) {
  if (result.status === 'fulfilled') {
    console.log('Success:', result.value);
  } else {
    console.error('Failed:', result.reason);
  }
}

Python: Sequential with Error Recovery

results = {}
for name, fn in [
    ("assets", lambda: client.maker.list_assets()),
    ("pairs", lambda: client.maker.list_pairs()),
]:
    try:
        results[name] = fn()
    except KaleidoError as e:
        print(f"Failed to fetch {name}: {e}")
        results[name] = None

Amount Handling

Always Use Raw Units for API Calls

The API works with raw (smallest unit) amounts. Convert display amounts before sending:
import { toSmallestUnits } from 'kaleidoswap-sdk';

// User enters 0.001 BTC
const userInput = 0.001;
const rawAmount = toSmallestUnits(userInput, 8);  // 100000

const quote = await client.maker.getQuote({
  from_asset: { asset_id: 'BTC', layer: 'BTC_LN', amount: rawAmount },
  to_asset: { asset_id: 'USDT', layer: 'RGB_LN' }
});

Use PrecisionHandler for Multi-Asset Apps

When working with multiple assets, use PrecisionHandler to avoid precision errors:
import { createPrecisionHandler } from 'kaleidoswap-sdk';

const handler = createPrecisionHandler(mappedAssets);

// Convert safely using asset ID
const raw = handler.toRawAmount(userInput, assetId);
const display = handler.toDisplayAmount(rawFromApi, assetId);

Node Operations

Check Node Before Using RLN

Always verify the node is configured:
if (!client.hasNode()) {
  throw new Error('Node URL required for this operation');
}

const balance = await client.rln.getBtcBalance();

WebSocket

Unsubscribe When Done

Always clean up WebSocket subscriptions:
const unsubscribe = await client.maker.streamQuotesByTicker(
  'BTC', 'USDT', 100000, onQuote
);

// Clean up when component unmounts or user navigates away
unsubscribe();

Handle Reconnection

Listen for reconnection events and update UI accordingly:
const ws = client.maker.enableWebSocket(wsUrl);

ws.on('disconnected', () => {
  // Show "reconnecting" indicator
});

ws.on('connected', () => {
  // Re-request quotes after reconnection
  ws.requestQuote({ /* ... */ });
});

ws.on('maxReconnectExceeded', () => {
  // Show "connection lost" error to user
});

Security

Never Expose API Keys in Client Code

API keys should only be used server-side. For browser applications, proxy API calls through your backend.

Validate User Input

Always validate amounts and addresses before sending to the API:
// Validate amount is within limits
const pairs = await client.maker.listPairs();
const pair = pairs.pairs.find(p =>
  p.base_asset_ticker === 'BTC' && p.quote_asset_ticker === 'USDT'
);

if (pair?.routes?.[0]) {
  const route = pair.routes[0];
  if (amount < route.min_from_amount || amount > route.max_from_amount) {
    throw new Error(`Amount must be between ${route.min_from_amount} and ${route.max_from_amount}`);
  }
}

Performance

Cache Static Data

Assets and trading pairs change infrequently. Cache them to reduce API calls:
let cachedPairs: ListPairsResponse | null = null;
let cacheTime = 0;

async function getPairs() {
  const now = Date.now();
  if (!cachedPairs || now - cacheTime > 60000) {  // 60 second cache
    cachedPairs = await client.maker.listPairs();
    cacheTime = now;
  }
  return cachedPairs;
}