# Client Package

## @ckboost/client SDK

### Overview

The `@ckboost/client` SDK provides a simple, type-safe way to integrate CKBoost acceleration services into your dApp. CKBoost reduces ckBTC conversion times from 1 hour (6 confirmations) to 7-10 minutes (1-2 confirmations) through a network of liquidity providers. We are planning to expend ckBoost and support other chain-key tokens (ckETH, in the future ckSOL, etc)&#x20;

#### Key Features

* 🚀 **Fast Integration**: Simple API with just two main functions
* 📝 **TypeScript First**: Full type safety and excellent developer experience
* ⚡ **Real-time Monitoring**: Track boost request status changes
* 🔒 **Secure**: Built on Internet Computer Protocol (ICP)
* 🎯 **dApp Ready**: Designed specifically for frontend integration

### Installation

```bash
npm install @ckboost/client
```

```bash
yarn add @ckboost/client
```

```bash
pnpm add @ckboost/client
```

### Quick Start

```typescript
import { ckTESTBTCClient, BoostStatus } from '@ckboost/client';

// Initialize client
const client = new ckTESTBTCClient({
  host: 'https://icp-api.io',
  timeout: 30000
});

// Create a boost request
const result = await client.generateDepositAddress({
  amount: '0.01',              // 0.01 ckTESTBTC
  maxFeePercentage: 1.5        // 1.5% maximum fee
});

if (result.success) {
  const { requestId, address, explorerUrl } = result.data;
  
  // Show deposit address to user
  console.log(`Send Bitcoin to: ${address}`);
  console.log(`Track at: ${explorerUrl}`);
  
  // Monitor status
  const statusResult = await client.getBoostRequest(requestId);
  if (statusResult.success) {
    console.log(`Status: ${statusResult.data.status}`);
  }
}
```

### API Reference

#### Client Initialization

**`ckTESTBTCClient`**

Creates a new client instance for ckTESTBTC (Bitcoin testnet).

```typescript
import { ckTESTBTCClient } from '@ckboost/client';

const client = new ckTESTBTCClient(config?: ClientConfig);
```

**Parameters:**

| Parameter | Type           | Default | Description                   |
| --------- | -------------- | ------- | ----------------------------- |
| `config`  | `ClientConfig` | `{}`    | Optional client configuration |

**ClientConfig:**

```typescript
interface ClientConfig {
  host?: string;     // ICP host URL (default: 'https://icp-api.io')
  timeout?: number;  // Request timeout in ms (default: 30000)
}
```

#### Core Methods

**`generateDepositAddress()`**

Creates a new boost request and returns deposit information.

```typescript
async generateDepositAddress(
  params: DepositAddressParams
): Promise<ApiResponse<DepositInfo>>
```

**Parameters:**

```typescript
interface DepositAddressParams {
  amount: string;                    // Amount in ckTESTBTC (e.g., "0.01")
  maxFeePercentage: number;          // Maximum fee as percentage (e.g., 1.5)
  confirmationsRequired?: number;    // Override default confirmations
  preferredBooster?: string;         // Specific booster principal ID
}
```

**Returns:**

```typescript
interface DepositInfo {
  requestId: string;           // Unique request identifier
  address: string;             // Bitcoin deposit address
  amount: string;              // Amount in ckTESTBTC
  amountRaw: string;           // Amount in satoshis
  maxFeePercentage: number;    // Maximum fee percentage
  explorerUrl: string;         // Block explorer URL
}
```

**`getBoostRequest()`**

Retrieves detailed information about a specific boost request.

```typescript
async getBoostRequest(
  requestId: string
): Promise<ApiResponse<BoostRequest>>
```

**Parameters:**

| Parameter   | Type     | Description                   |
| ----------- | -------- | ----------------------------- |
| `requestId` | `string` | The unique request identifier |

**Returns:**

```typescript
interface BoostRequest {
  id: string;                    // Request ID
  status: BoostStatus;           // Current status
  amount: string;                // Requested amount in ckTESTBTC
  receivedAmount: string;        // Amount received so far
  maxFeePercentage: number;      // Maximum fee percentage
  confirmationsRequired: number;  // Required confirmations
  depositAddress?: string;       // Bitcoin deposit address
  booster?: string;             // Assigned booster principal
  createdAt: number;            // Creation timestamp (ms)
  updatedAt: number;            // Last update timestamp (ms)
}
```

**`getPendingBoostRequests()`**

Retrieves all pending boost requests.

```typescript
async getPendingBoostRequests(): Promise<ApiResponse<BoostRequest[]>>
```

#### Utility Methods

**`getTokenConfig()`**

Returns the current token configuration.

```typescript
getTokenConfig(): TokenConfig
```

**Returns:**

```typescript
interface TokenConfig {
  token: SupportedToken;         // Token type
  minimumAmount: string;         // Minimum boost amount
  maximumAmount: string;         // Maximum boost amount
  standardFee: string;           // Standard fee amount
  confirmationsRequired: number; // Default confirmations
  decimals: number;             // Token decimals (8 for Bitcoin)
  isTestnet: boolean;           // Whether this is testnet
  blockExplorerUrl: string;     // Block explorer base URL
}
```

**`rawToTokenAmount()`**

Converts raw amount (satoshis) to token amount (ckTESTBTC).

```typescript
rawToTokenAmount(rawAmount: string | bigint): string
```

**`tokenToRawAmount()`**

Converts token amount (ckTESTBTC) to raw amount (satoshis).

```typescript
tokenToRawAmount(tokenAmount: string): string
```

### Types Reference

#### Enums

**`BoostStatus`**

```typescript
enum BoostStatus {
  PENDING = 'pending',       // Waiting for Bitcoin deposit
  ACTIVE = 'active',         // Processing the boost
  COMPLETED = 'completed',   // ckTESTBTC delivered
  CANCELLED = 'cancelled'    // Request cancelled
}
```

**`SupportedToken`**

```typescript
enum SupportedToken {
  CK_TEST_BTC = 'ckTESTBTC'
}
```

**`CKBoostErrorType`**

```typescript
enum CKBoostErrorType {
  INVALID_AMOUNT = 'INVALID_AMOUNT',
  NETWORK_ERROR = 'NETWORK_ERROR',
  REQUEST_NOT_FOUND = 'REQUEST_NOT_FOUND',
  CANISTER_ERROR = 'CANISTER_ERROR',
  VALIDATION_ERROR = 'VALIDATION_ERROR',
  UNKNOWN_ERROR = 'UNKNOWN_ERROR'
}
```

#### Response Types

**`ApiResponse<T>`**

All API methods return this discriminated union type:

```typescript
type ApiResponse<T> = 
  | { success: true; data: T; }
  | { success: false; error: CKBoostError; };

interface CKBoostError {
  type: CKBoostErrorType;
  message: string;
  details?: any;
}
```

### Examples

#### Basic Integration

```typescript
import { ckTESTBTCClient, BoostStatus } from '@ckboost/client';

class BitcoinAccelerator {
  private client = new ckTESTBTCClient();

  async createBoost(amount: string, maxFee: number) {
    const result = await this.client.generateDepositAddress({
      amount,
      maxFeePercentage: maxFee
    });

    if (result.success) {
      return {
        success: true,
        depositAddress: result.data.address,
        requestId: result.data.requestId,
        explorerUrl: result.data.explorerUrl
      };
    } else {
      return {
        success: false,
        error: result.error.message
      };
    }
  }

  async checkStatus(requestId: string) {
    const result = await this.client.getBoostRequest(requestId);
    
    if (result.success) {
      const request = result.data;
      return {
        status: request.status,
        progress: {
          requested: request.amount,
          received: request.receivedAmount,
          percentage: (parseFloat(request.receivedAmount) / parseFloat(request.amount)) * 100
        },
        isComplete: request.status === BoostStatus.COMPLETED
      };
    }
    
    return { error: result.error.message };
  }
}
```

#### React Hook Integration

```typescript
import { useState, useEffect } from 'react';
import { ckTESTBTCClient, BoostRequest, BoostStatus } from '@ckboost/client';

export function useBoostRequest(requestId?: string) {
  const [request, setRequest] = useState<BoostRequest | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const client = new ckTESTBTCClient();

  useEffect(() => {
    if (!requestId) return;

    const pollStatus = async () => {
      setLoading(true);
      setError(null);

      try {
        const result = await client.getBoostRequest(requestId);
        
        if (result.success) {
          setRequest(result.data);
        } else {
          setError(result.error.message);
        }
      } catch (err) {
        setError('Failed to fetch boost request');
      } finally {
        setLoading(false);
      }
    };

    pollStatus();
    
    // Poll every 10 seconds until complete
    const interval = setInterval(() => {
      if (request?.status !== BoostStatus.COMPLETED && 
          request?.status !== BoostStatus.CANCELLED) {
        pollStatus();
      }
    }, 10000);

    return () => clearInterval(interval);
  }, [requestId, request?.status]);

  return { request, loading, error };
}
```

#### Complete dApp Integration

```typescript
import { ckTESTBTCClient, BoostStatus } from '@ckboost/client';

class CKBoostService {
  private client: ckTESTBTCClient;
  private activeRequests = new Map<string, NodeJS.Timeout>();

  constructor() {
    this.client = new ckTESTBTCClient({
      host: 'https://icp-api.io',
      timeout: 30000
    });
  }

  async createBoostRequest(amount: string, maxFeePercentage: number) {
    // Validate amount first
    const config = this.client.getTokenConfig();
    const amountNum = parseFloat(amount);
    const minAmount = parseFloat(config.minimumAmount);
    const maxAmount = parseFloat(config.maximumAmount);

    if (amountNum < minAmount || amountNum > maxAmount) {
      return {
        success: false,
        error: `Amount must be between ${minAmount} and ${maxAmount} ckTESTBTC`
      };
    }

    const result = await this.client.generateDepositAddress({
      amount,
      maxFeePercentage
    });

    if (result.success) {
      // Start monitoring this request
      this.startMonitoring(result.data.requestId);
      
      return {
        success: true,
        data: result.data
      };
    }

    return {
      success: false,
      error: result.error.message
    };
  }

  private startMonitoring(requestId: string, onUpdate?: (request: BoostRequest) => void) {
    // Clear existing timeout for this request
    if (this.activeRequests.has(requestId)) {
      clearTimeout(this.activeRequests.get(requestId)!);
    }

    const poll = async () => {
      const result = await this.client.getBoostRequest(requestId);
      
      if (result.success) {
        const request = result.data;
        
        // Notify about update
        if (onUpdate) {
          onUpdate(request);
        }

        // Continue polling if not in final state
        if (request.status !== BoostStatus.COMPLETED && 
            request.status !== BoostStatus.CANCELLED) {
          const timeout = setTimeout(poll, 10000); // Poll every 10 seconds
          this.activeRequests.set(requestId, timeout);
        } else {
          this.activeRequests.delete(requestId);
        }
      }
    };

    // Start immediate poll
    poll();
  }

  stopMonitoring(requestId: string) {
    if (this.activeRequests.has(requestId)) {
      clearTimeout(this.activeRequests.get(requestId)!);
      this.activeRequests.delete(requestId);
    }
  }

  destroy() {
    // Clean up all active monitoring
    this.activeRequests.forEach(timeout => clearTimeout(timeout));
    this.activeRequests.clear();
  }
}
```

### Error Handling

#### Error Types

The SDK provides specific error types to help you handle different scenarios:

```typescript
import { CKBoostErrorType } from '@ckboost/client';

async function handleBoostRequest() {
  const result = await client.generateDepositAddress({
    amount: '0.01',
    maxFeePercentage: 1.5
  });

  if (!result.success) {
    switch (result.error.type) {
      case CKBoostErrorType.INVALID_AMOUNT:
        // Show amount validation error to user
        alert('Please enter a valid amount between the minimum and maximum limits');
        break;
        
      case CKBoostErrorType.NETWORK_ERROR:
        // Show network error and retry option
        alert('Network error. Please check your connection and try again');
        break;
        
      case CKBoostErrorType.CANISTER_ERROR:
        // Backend service error
        alert('Service temporarily unavailable. Please try again later');
        break;
        
      default:
        // Generic error handling
        alert(`Error: ${result.error.message}`);
    }
  }
}
```

#### Best Practices

1. **Always check the `success` property** before accessing `data`
2. **Provide user-friendly error messages** based on error types
3. **Implement retry logic** for network errors
4. **Validate amounts** before making requests
5. **Monitor request status** until completion

### Configuration

#### Canister IDs

The SDK includes the required canister IDs:

```typescript
import { ckTESTBTC_CANISTER_IDS } from '@ckboost/client';

console.log('Backend Canister:', ckTESTBTC_CANISTER_IDS.CKBOOST_BACKEND);
console.log('Ledger Canister:', ckTESTBTC_CANISTER_IDS.CKTESTBTC_LEDGER);
```

#### Network Configuration

For production applications, use the default configuration:

```typescript
const client = new ckTESTBTCClient({
  host: 'https://icp-api.io',  // Production ICP host
  timeout: 30000               // 30 second timeout
});
```

For development, you might want to use a local replica:

```typescript
const client = new ckTESTBTCClient({
  host: 'http://localhost:4943',  // Local dfx replica
  timeout: 10000                  // Shorter timeout for local testing
});
```

### Monitoring and Real-time Updates

#### Polling Strategy

For production applications, implement efficient polling:

```typescript
class BoostMonitor {
  private intervals = new Map<string, NodeJS.Timeout>();

  startMonitoring(requestId: string, callback: (request: BoostRequest) => void) {
    let attempts = 0;
    const maxAttempts = 360; // Monitor for 1 hour max (10s intervals)
    
    const poll = async () => {
      attempts++;
      
      const result = await client.getBoostRequest(requestId);
      if (result.success) {
        const request = result.data;
        callback(request);
        
        // Stop if complete or max attempts reached
        if (request.status === BoostStatus.COMPLETED || 
            request.status === BoostStatus.CANCELLED ||
            attempts >= maxAttempts) {
          this.stopMonitoring(requestId);
          return;
        }
      }
      
      // Continue polling with exponential backoff
      const delay = Math.min(10000 + (attempts * 1000), 30000);
      const timeout = setTimeout(poll, delay);
      this.intervals.set(requestId, timeout);
    };
    
    poll();
  }
  
  stopMonitoring(requestId: string) {
    const interval = this.intervals.get(requestId);
    if (interval) {
      clearTimeout(interval);
      this.intervals.delete(requestId);
    }
  }
}
```

#### WebSocket Alternative

For real-time updates, consider implementing WebSocket connections to the backend canister (when available) instead of polling.

### Troubleshooting

#### Common Issues

**Import Errors**

```typescript
// ❌ Don't do this
import CKBoostClient from '@ckboost/client';

// ✅ Do this
import { ckTESTBTCClient } from '@ckboost/client';
```

**Type Errors**

Make sure you have TypeScript configured properly:

```json
// tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "node",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true
  }
}
```

**Network Errors**

If you're getting network errors:

1. Check your internet connection
2. Verify the ICP host URL is correct
3. Ensure the canister IDs are valid
4. Try increasing the timeout value

### Support

* **Documentation**: [docs.ckboost.com](https://docs.ckboost.com)
* **GitHub**: [github.com/ckboost/ckboost-packages](https://github.com/ckboost/ckboost-packages)
* **Issues**: Report bugs and feature requests on GitHub
