@reflow-xyz/sdk
v1.0.0
Published
Cloak Privacy Protocol SDK for Solana - Deposit and withdraw SOL/SPL tokens with zero-knowledge proofs
Downloads
98
Maintainers
Readme
@cloak-labs/sdk
Official SDK for the Cloak Privacy Protocol on Solana. Deposit and withdraw SOL and SPL tokens with zero-knowledge proof privacy guarantees.
Features
- Privacy-Preserving Transfers: Zero-knowledge proofs ensure transaction privacy
- SOL Support: Deposit and withdraw native SOL
- SPL Token Support: Full support for SPL tokens (USDC, USDT, etc.)
- Delayed Withdrawals: Optional delayed withdrawals for enhanced security
- Keypair-Based: Simple initialization with Solana Keypair
- TypeScript: Full TypeScript support with comprehensive types
- Production Ready: Built on audited smart contracts
Installation
npm install @cloak-labs/sdk
# or
yarn add @cloak-labs/sdk
# or
pnpm add @cloak-labs/sdkQuick Start
import { CloakSDK, Connection, Keypair } from '@cloak-labs/sdk';
// Initialize connection and keypair
const connection = new Connection('https://api.devnet.solana.com');
const keypair = Keypair.fromSecretKey(secretKeyBytes);
// Create SDK instance
const sdk = new CloakSDK({
connection,
signer: keypair,
verbose: true // Optional: enable logging
});
// Initialize SDK (required before use)
await sdk.initialize();
// Now you can use all SDK functionsAPI Reference
Constructor
new CloakSDK(config: CloakSDKConfig)
Creates a new SDK instance.
Parameters:
config.connection(Connection): Solana connection instanceconfig.signer(TransactionSigner | Keypair): User's Solana keypair or wallet adapter for signing transactionsconfig.relayerUrl(string, optional): Custom relayer URL. Defaults to production relayerconfig.programId(string, optional): Custom program ID. Defaults to mainnet programconfig.verbose(boolean, optional): Enable verbose logging. Default: false
Initialization
await sdk.initialize()
Initializes the SDK by loading the Poseidon hasher and generating account signatures. Must be called before any other operations.
await sdk.initialize();SOL Operations
await sdk.depositSol(options: DepositOptions): Promise<DepositResult>
Deposit SOL into the privacy pool.
Parameters:
options.amount(number): Amount in SOL (e.g., 0.5 for half a SOL)options.onStatus((status: string) => void, optional): Callback for status updates
Returns: DepositResult
success(boolean): Whether deposit succeededsignature(string, optional): Transaction signatureerror(string, optional): Error message if failed
Example:
const result = await sdk.depositSol({
amount: 0.5,
onStatus: (status) => console.log('Status:', status)
});
if (result.success) {
console.log('Deposit successful:', result.signature);
console.log(`View on explorer: https://explorer.solana.com/tx/${result.signature}`);
}await sdk.withdrawSol(options: WithdrawOptions): Promise<WithdrawResult>
Withdraw SOL from the privacy pool.
Parameters:
options.recipientAddress(PublicKey | string): Recipient's wallet addressoptions.amount(number): Amount in SOL to withdrawoptions.delayMinutes(number, optional): Delay before execution (0 for immediate). Max: 10080 (7 days)options.onStatus((status: string) => void, optional): Callback for status updates
Returns: WithdrawResult
isPartial(boolean): Whether withdrawal was partial (insufficient balance)success(boolean): Whether withdrawal succeededsignature(string, optional): Transaction signature (for immediate withdrawals)delayedWithdrawalId(number, optional): ID for delayed withdrawalsexecuteAt(string, optional): ISO timestamp when delayed withdrawal will executeerror(string, optional): Error message if failed
Example (Immediate):
const result = await sdk.withdrawSol({
recipientAddress: 'recipient-pubkey-here',
amount: 0.3,
});
if (result.success) {
console.log('Withdrawal successful!');
if (result.isPartial) {
console.log('Note: Partial withdrawal due to insufficient balance');
}
}Example (Delayed):
const result = await sdk.withdrawSol({
recipientAddress: new PublicKey('...'),
amount: 0.3,
delayMinutes: 30, // Execute after 30 minutes
});
if (result.success) {
console.log('Withdrawal scheduled!');
console.log('ID:', result.delayedWithdrawalId);
console.log('Will execute at:', result.executeAt);
}await sdk.batchDepositSol(options: BatchDepositOptions): Promise<BatchDepositResult>
Perform multiple SOL deposits with optimized denomination breakdown and single wallet signature.
Parameters:
options.amount(number): Total amount in SOL to depositoptions.onStatus((status: string) => void, optional): Callback for status updates
Returns: BatchDepositResult
success(boolean): Whether all deposits succeededtotalDeposited(number): Total amount depositedtransactionCount(number): Number of transactions executedsignatures(string[]): Array of transaction signatureserror(string, optional): Error message if failed
Example:
// Deposit 1.5 SOL broken into optimal denominations
const result = await sdk.batchDepositSol({
amount: 1.5,
onStatus: (status) => console.log('Batch:', status)
});
if (result.success) {
console.log(`Deposited ${result.totalDeposited} SOL in ${result.transactionCount} transactions`);
result.signatures.forEach((sig, i) => {
console.log(`Transaction ${i + 1}: ${sig}`);
});
}SPL Token Operations
await sdk.depositSpl(options: DepositSplOptions): Promise<DepositResult>
Deposit SPL tokens into the privacy pool.
Parameters:
options.amount(number): Amount in base units (e.g., 1000000 for 1 USDC with 6 decimals)options.mintAddress(string): SPL token mint addressoptions.onStatus((status: string) => void, optional): Callback for status updates
Example:
// Deposit 1 USDC (6 decimals)
const result = await sdk.depositSpl({
amount: 1_000_000,
mintAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC mint
onStatus: (status) => console.log(status)
});
if (result.success) {
console.log('USDC deposit successful:', result.signature);
}await sdk.withdrawSpl(options: WithdrawSplOptions): Promise<WithdrawResult>
Withdraw SPL tokens from the privacy pool.
Parameters:
options.recipientAddress(PublicKey | string): Recipient's wallet addressoptions.amount(number): Amount in base unitsoptions.mintAddress(string): SPL token mint addressoptions.delayMinutes(number, optional): Delay before executionoptions.onStatus((status: string) => void, optional): Callback for status updates
Example:
// Immediate SPL withdrawal
const result = await sdk.withdrawSpl({
recipientAddress: 'recipient-pubkey-here',
amount: 500_000, // 0.5 USDC
mintAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
});
// Delayed SPL withdrawal
const delayedResult = await sdk.withdrawSpl({
recipientAddress: new PublicKey('...'),
amount: 500_000,
mintAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
delayMinutes: 60, // Execute after 1 hour
});Balance Queries
await sdk.getSolBalance(): Promise<UtxoBalance>
Get your SOL balance in the privacy pool.
Returns: UtxoBalance
total(BN): Total balance in lamportscount(number): Number of UTXOsmintAddress(string): Mint address
Example:
const balance = await sdk.getSolBalance();
console.log('SOL balance:', balance.total.toNumber() / 1e9, 'SOL');
console.log('Number of UTXOs:', balance.count);await sdk.getSplBalance(mintAddress: string): Promise<UtxoBalance>
Get your SPL token balance in the privacy pool.
Parameters:
mintAddress(string): SPL token mint address
Example:
const usdcBalance = await sdk.getSplBalance('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
console.log('USDC balance:', usdcBalance.total.toNumber() / 1e6);
console.log('Number of UTXOs:', usdcBalance.count);Utility Methods
sdk.getPublicKey(): PublicKey
Get the user's public key.
sdk.getConnection(): Connection
Get the Solana connection instance.
Batch Planning Utilities
planBatchDeposits(totalAmount: number): BatchDepositPlan | null
Plan how to split a large deposit into denomination-based transactions.
previewBatchDeposit(totalAmount: number): BatchPreview | null
Preview batch deposit operations without executing them.
Example:
import { planBatchDeposits, previewBatchDeposit } from '@cloak-labs/sdk';
const preview = previewBatchDeposit(2.5); // 2.5 SOL
if (preview) {
console.log(`Will create ${preview.numTransactions} transactions`);
console.log(`Estimated time: ${preview.estimatedTime} seconds`);
console.log('Breakdown:', preview.breakdown);
}Complete Example
import { CloakSDK, Connection, Keypair, LAMPORTS_PER_SOL } from '@cloak-labs/sdk';
import fs from 'fs';
async function main() {
// Load keypair from file
const secretKey = JSON.parse(
fs.readFileSync('/path/to/keypair.json', 'utf-8')
);
const keypair = Keypair.fromSecretKey(new Uint8Array(secretKey));
// Initialize SDK
const connection = new Connection('https://api.devnet.solana.com');
const sdk = new CloakSDK({
connection,
signer: keypair,
verbose: true,
});
await sdk.initialize();
console.log('SDK initialized with wallet:', sdk.getPublicKey().toString());
// Check current balance
const balance = await sdk.getSolBalance();
console.log('Current privacy pool balance:', balance.total.toNumber() / LAMPORTS_PER_SOL, 'SOL');
// Deposit SOL
console.log('\nDepositing 0.1 SOL...');
const depositResult = await sdk.depositSol({
amount: 0.1,
onStatus: (status) => console.log(' →', status),
});
if (!depositResult.success) {
console.error('Deposit failed:', depositResult.error);
return;
}
console.log('Deposit successful:', depositResult.signature);
// Wait a bit for relayer to update
console.log('\nWaiting for relayer to update...');
await new Promise(resolve => setTimeout(resolve, 10000));
// Check updated balance
const newBalance = await sdk.getSolBalance();
console.log('New privacy pool balance:', newBalance.total.toNumber() / LAMPORTS_PER_SOL, 'SOL');
// Withdraw with delay
console.log('\nScheduling withdrawal of 0.05 SOL (30 minute delay)...');
const withdrawResult = await sdk.withdrawSol({
recipientAddress: sdk.getPublicKey(), // Withdraw to self
amount: 0.05,
delayMinutes: 30,
onStatus: (status) => console.log(' →', status),
});
if (!withdrawResult.success) {
console.error('Withdrawal scheduling failed:', withdrawResult.error);
return;
}
console.log('Withdrawal scheduled!');
console.log(' ID:', withdrawResult.delayedWithdrawalId);
console.log(' Will execute at:', withdrawResult.executeAt);
}
main().catch(console.error);Error Handling
try {
const result = await sdk.depositSol({ amount: 0.5 });
if (!result.success) {
console.error('Deposit failed:', result.error);
// Handle specific errors
if (result.error?.includes('Insufficient balance')) {
console.log('You need more SOL in your wallet');
}
}
} catch (error) {
console.error('Unexpected error:', error);
}Common SPL Token Mint Addresses
- USDC:
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v - USDT:
Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB - SOL (native): Use
depositSol/withdrawSolmethods instead
Fee Structure
- Deposit Fee: 0.3% of deposit amount
- Withdrawal Fee: 0.3% of withdrawal amount
Fees are automatically deducted from the transaction amounts.
Security Considerations
- Keypair Safety: Never share or commit your secret key
- Delayed Withdrawals: Use delays for large amounts to detect unauthorized access
- Balance Verification: Always check balances before operations
- Error Handling: Implement proper error handling in production
TypeScript Support
The SDK is written in TypeScript and provides full type definitions:
import type {
CloakSDKConfig,
DepositOptions,
DepositResult,
WithdrawOptions,
WithdrawResult,
UtxoBalance,
} from '@cloak-labs/sdk';Building from Source
# Clone the repository
git clone https://github.com/reflow-xyz/cloaksdk
cd cloak-sdk/
# Install dependencies
pnpm install
# Build
ts-node example.tsSupport
- GitHub Issues: Report bugs or request features
- Documentation: Full protocol documentation
