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)
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
npm install @ckboost/client
yarn add @ckboost/client
pnpm add @ckboost/client
Quick Start
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).
import { ckTESTBTCClient } from '@ckboost/client';
const client = new ckTESTBTCClient(config?: ClientConfig);
Parameters:
config
ClientConfig
{}
Optional client configuration
ClientConfig:
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.
async generateDepositAddress(
params: DepositAddressParams
): Promise<ApiResponse<DepositInfo>>
Parameters:
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:
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.
async getBoostRequest(
requestId: string
): Promise<ApiResponse<BoostRequest>>
Parameters:
requestId
string
The unique request identifier
Returns:
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.
async getPendingBoostRequests(): Promise<ApiResponse<BoostRequest[]>>
Utility Methods
getTokenConfig()
Returns the current token configuration.
getTokenConfig(): TokenConfig
Returns:
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).
rawToTokenAmount(rawAmount: string | bigint): string
tokenToRawAmount()
Converts token amount (ckTESTBTC) to raw amount (satoshis).
tokenToRawAmount(tokenAmount: string): string
Types Reference
Enums
BoostStatus
enum BoostStatus {
PENDING = 'pending', // Waiting for Bitcoin deposit
ACTIVE = 'active', // Processing the boost
COMPLETED = 'completed', // ckTESTBTC delivered
CANCELLED = 'cancelled' // Request cancelled
}
SupportedToken
enum SupportedToken {
CK_TEST_BTC = 'ckTESTBTC'
}
CKBoostErrorType
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:
type ApiResponse<T> =
| { success: true; data: T; }
| { success: false; error: CKBoostError; };
interface CKBoostError {
type: CKBoostErrorType;
message: string;
details?: any;
}
Examples
Basic Integration
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
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
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:
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
Always check the
success
property before accessingdata
Provide user-friendly error messages based on error types
Implement retry logic for network errors
Validate amounts before making requests
Monitor request status until completion
Configuration
Canister IDs
The SDK includes the required canister IDs:
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:
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:
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:
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
// ❌ 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:
// tsconfig.json
{
"compilerOptions": {
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
}
}
Network Errors
If you're getting network errors:
Check your internet connection
Verify the ICP host URL is correct
Ensure the canister IDs are valid
Try increasing the timeout value
Support
Documentation: docs.ckboost.com
Issues: Report bugs and feature requests on GitHub
Last updated