⭕
zkvoid Docs
  • ☀️Overview
  • 📗Getting Started
    • ⚙️Setup Token Account
    • ⬇️Deposit Tokens
    • 👨‍🔬Apply Pending Balance
    • 🛫Send Confidential Transfers
    • ⬆️Withdraw Tokens
    • 🤔Understanding Balances
  • 🔎Void vs. CLI
  • ⭕cSOL
  • 📶API
    • ✍️Documentation
    • 👨‍🍳Cookbook
    • 👨‍🔧Deep Dive
Powered by GitBook
On this page
  • ZK Void Confidential Transfer API Documentation
  • Overview
  • Table of Contents
  • Authentication
  • API Response Format
  • Endpoints
  • Error Handling
  • Integration Guide
  • Code Examples
  • Security Considerations
  1. API

Deep Dive

ZK Void Confidential Transfer API Documentation

Base URL: https://api.zkvoid.com

Overview

The ZK Void Confidential Transfer API enables developers to integrate confidential token transfers into their dApps using Solana's SPL Token 2022 confidential transfer extensions. This API provides a trusted backend model where the service manages encryption keys and generates zero-knowledge proofs, while users maintain control of their wallets and pay their own transaction fees.

Table of Contents

  • Authentication

  • API Response Format

  • Endpoints

  • Error Handling

  • Integration Guide

  • Code Examples

  • Security Considerations

Authentication

The API uses a signature-based authentication system where users sign a deterministic message with their wallet to derive encryption keys. This ensures that only the wallet owner can access their confidential balances.

Key Derivation Message

Confidential Transfer Key Derivation: {wallet_public_key}

API Response Format

All API responses follow a consistent format:

{
  "success": boolean,
  "data": T | null,
  "error": string | null
}

Endpoints

1. Health Check

GET /health

Check if the API service is running.

Response:

{
  "success": true,
  "data": "Confidential Transfer Service is running",
  "error": null
}

2. Setup Confidential Account

POST /setup-account

Configure a token account to enable confidential transfers. This is a one-time setup per token.

Request Body:

{
  "owner_pubkey": "string",     // Wallet public key
  "signature": "string",        // Base64-encoded signature for key derivation
  "mint_address": "string"      // SPL Token 2022 mint address
}

Response:

{
  "success": true,
  "data": {
    "transaction": "string",    // Base64-encoded transaction to sign
    "description": "string"     // Human-readable description
  },
  "error": null
}

3. Deposit Tokens

POST /deposit

Convert regular tokens to confidential state.

Request Body:

{
  "owner_pubkey": "string",     // Wallet public key
  "signature": "string",        // Base64-encoded signature for key derivation
  "amount": number,             // Amount in smallest token units
  "mint_address": "string"      // SPL Token 2022 mint address
}

Response:

{
  "success": true,
  "data": {
    "transaction": "string",    // Base64-encoded transaction to sign
    "description": "string"     // Human-readable description
  },
  "error": null
}

4. Apply Pending Balance

POST /apply-pending-balance

Apply pending balance to make it available for transfers.

Request Body:

{
  "owner_pubkey": "string",     // Wallet public key
  "signature": "string",        // Base64-encoded signature for key derivation
  "mint_address": "string"      // SPL Token 2022 mint address
}

Response:

{
  "success": true,
  "data": {
    "transaction": "string",    // Base64-encoded transaction to sign
    "description": "string"     // Human-readable description
  },
  "error": null
}

5. Get Confidential Balance

POST /balance

Decrypt and retrieve confidential balance information.

Request Body:

{
  "owner_pubkey": "string",     // Wallet public key
  "signature": "string",        // Base64-encoded signature for key derivation
  "mint_address": "string"      // SPL Token 2022 mint address
}

Response:

{
  "success": true,
  "data": {
    "available_balance": number,  // Available confidential balance
    "pending_balance": number,    // Pending balance (needs to be applied)
    "public_balance": number      // Regular (non-confidential) balance
  },
  "error": null
}

6. Confidential Transfer

POST /transfer

Execute a confidential token transfer between wallets.

Request Body:

{
  "sender_pubkey": "string",      // Sender wallet public key
  "sender_signature": "string",   // Base64-encoded signature for key derivation
  "recipient_pubkey": "string",   // Recipient wallet public key
  "amount": number,               // Amount in smallest token units
  "mint_address": "string"        // SPL Token 2022 mint address
}

Response:

{
  "success": true,
  "data": {
    "transactions": ["string"],           // Array of Base64-encoded transactions
    "descriptions": ["string"],           // Human-readable descriptions
    "is_atomic": false,                   // Whether transactions must be executed atomically
    "additional_signers": ["string"]      // Base64-encoded additional keypairs (optional)
  },
  "error": null
}

7. Withdraw Tokens

POST /withdraw

Convert confidential tokens back to regular state.

Request Body:

{
  "owner_pubkey": "string",     // Wallet public key
  "signature": "string",        // Base64-encoded signature for key derivation
  "amount": number,             // Amount in smallest token units
  "mint_address": "string"      // SPL Token 2022 mint address
}

Response:

{
  "success": true,
  "data": {
    "transactions": ["string"],           // Array of Base64-encoded transactions
    "descriptions": ["string"],           // Human-readable descriptions
    "is_atomic": false,                   // Whether transactions must be executed atomically
    "additional_signers": ["string"]      // Base64-encoded additional keypairs (optional)
  },
  "error": null
}

Error Handling

The API returns appropriate HTTP status codes and error messages:

  • 400 Bad Request: Invalid input parameters

  • 404 Not Found: Account or resource not found

  • 500 Internal Server Error: Server-side errors

Error Response Example:

{
  "success": false,
  "data": null,
  "error": "Invalid signature: signature verification failed"
}

Integration Guide

Prerequisites

  1. SPL Token 2022 Mint: Your token must be created with the confidential transfer extension

  2. Wallet Integration: Support for message signing (Phantom, Solflare, etc.)

  3. Solana Connection: RPC connection for transaction submission

Basic Integration Steps

  1. Setup Account: Call /setup-account to enable confidential transfers

  2. Deposit Tokens: Use /deposit to convert regular tokens to confidential

  3. Apply Pending: Call /apply-pending-balance to make deposited tokens available

  4. Transfer: Use /transfer for confidential transfers between wallets

  5. Check Balance: Use /balance to view confidential balances

  6. Withdraw: Use /withdraw to convert back to regular tokens

Code Examples

JavaScript/TypeScript Integration

// Configuration
const API_BASE_URL = 'https://api.zkvoid.com';
const MINT_ADDRESS = 'your_token_mint_address';

// Helper function to call API
async function callAPI<T>(endpoint: string, data: any): Promise<T> {
  const response = await fetch(`${API_BASE_URL}${endpoint}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  });

  if (!response.ok) {
    throw new Error(`API request failed: ${response.statusText}`);
  }

  const result = await response.json();
  if (!result.success) {
    throw new Error(result.error);
  }

  return result.data;
}

// Generate signature for key derivation
async function getKeyDerivationSignature(wallet: any): Promise<string> {
  const message = `Confidential Transfer Key Derivation: ${wallet.publicKey.toString()}`;
  const messageBytes = new TextEncoder().encode(message);
  const signature = await wallet.signMessage(messageBytes);
  return Buffer.from(signature).toString('base64');
}

// Setup confidential account
async function setupConfidentialAccount(wallet: any, mintAddress: string) {
  const signature = await getKeyDerivationSignature(wallet);
  
  const response = await callAPI('/setup-account', {
    owner_pubkey: wallet.publicKey.toString(),
    signature: signature,
    mint_address: mintAddress,
  });

  // Sign and submit the transaction
  const transaction = Transaction.from(Buffer.from(response.transaction, 'base64'));
  const signedTx = await wallet.signTransaction(transaction);
  const txSignature = await connection.sendRawTransaction(signedTx.serialize());
  
  return txSignature;
}

// Get confidential balance
async function getConfidentialBalance(wallet: any, mintAddress: string) {
  const signature = await getKeyDerivationSignature(wallet);
  
  const balance = await callAPI('/balance', {
    owner_pubkey: wallet.publicKey.toString(),
    signature: signature,
    mint_address: mintAddress,
  });

  return {
    available: balance.available_balance,
    pending: balance.pending_balance,
    public: balance.public_balance,
  };
}

// Deposit tokens to confidential balance
async function depositTokens(wallet: any, amount: number, mintAddress: string) {
  const signature = await getKeyDerivationSignature(wallet);
  
  const response = await callAPI('/deposit', {
    owner_pubkey: wallet.publicKey.toString(),
    signature: signature,
    amount: amount,
    mint_address: mintAddress,
  });

  // Sign and submit the transaction
  const transaction = Transaction.from(Buffer.from(response.transaction, 'base64'));
  const signedTx = await wallet.signTransaction(transaction);
  const txSignature = await connection.sendRawTransaction(signedTx.serialize());
  
  return txSignature;
}

// Execute confidential transfer
async function confidentialTransfer(
  wallet: any, 
  recipientAddress: string, 
  amount: number, 
  mintAddress: string
) {
  const signature = await getKeyDerivationSignature(wallet);
  
  const response = await callAPI('/transfer', {
    sender_pubkey: wallet.publicKey.toString(),
    sender_signature: signature,
    recipient_pubkey: recipientAddress,
    amount: amount,
    mint_address: mintAddress,
  });

  const signatures = [];
  
  // Execute transactions sequentially
  for (let i = 0; i < response.transactions.length; i++) {
    const transaction = Transaction.from(Buffer.from(response.transactions[i], 'base64'));
    
    // Handle additional signers if present
    if (response.additional_signers?.[i]) {
      const signerBytes = Buffer.from(response.additional_signers[i], 'base64');
      // Add additional signers to transaction
      // (Implementation depends on your specific needs)
    }
    
    const signedTx = await wallet.signTransaction(transaction);
    const txSignature = await connection.sendRawTransaction(signedTx.serialize());
    signatures.push(txSignature);
  }
  
  return signatures;
}

React Hook Example

import { useWallet } from '@solana/wallet-adapter-react';
import { useState, useCallback } from 'react';

export function useConfidentialTransfer(mintAddress: string) {
  const wallet = useWallet();
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const setupAccount = useCallback(async () => {
    if (!wallet.publicKey || !wallet.signMessage) {
      throw new Error('Wallet not connected');
    }

    setLoading(true);
    setError(null);

    try {
      const signature = await setupConfidentialAccount(wallet, mintAddress);
      return signature;
    } catch (err) {
      const errorMsg = err instanceof Error ? err.message : 'Unknown error';
      setError(errorMsg);
      throw err;
    } finally {
      setLoading(false);
    }
  }, [wallet, mintAddress]);

  const getBalance = useCallback(async () => {
    if (!wallet.publicKey || !wallet.signMessage) {
      throw new Error('Wallet not connected');
    }

    setLoading(true);
    setError(null);

    try {
      const balance = await getConfidentialBalance(wallet, mintAddress);
      return balance;
    } catch (err) {
      const errorMsg = err instanceof Error ? err.message : 'Unknown error';
      setError(errorMsg);
      throw err;
    } finally {
      setLoading(false);
    }
  }, [wallet, mintAddress]);

  const deposit = useCallback(async (amount: number) => {
    if (!wallet.publicKey || !wallet.signMessage) {
      throw new Error('Wallet not connected');
    }

    setLoading(true);
    setError(null);

    try {
      const signature = await depositTokens(wallet, amount, mintAddress);
      return signature;
    } catch (err) {
      const errorMsg = err instanceof Error ? err.message : 'Unknown error';
      setError(errorMsg);
      throw err;
    } finally {
      setLoading(false);
    }
  }, [wallet, mintAddress]);

  const transfer = useCallback(async (recipientAddress: string, amount: number) => {
    if (!wallet.publicKey || !wallet.signMessage) {
      throw new Error('Wallet not connected');
    }

    setLoading(true);
    setError(null);

    try {
      const signatures = await confidentialTransfer(wallet, recipientAddress, amount, mintAddress);
      return signatures;
    } catch (err) {
      const errorMsg = err instanceof Error ? err.message : 'Unknown error';
      setError(errorMsg);
      throw err;
    } finally {
      setLoading(false);
    }
  }, [wallet, mintAddress]);

  return {
    setupAccount,
    getBalance,
    deposit,
    transfer,
    loading,
    error,
  };
}

Python Integration Example

import requests
import base64
from solana.keypair import Keypair
from solana.publickey import PublicKey

class ConfidentialTransferAPI:
    def __init__(self, base_url="https://api.zkvoid.com"):
        self.base_url = base_url
    
    def _call_api(self, endpoint, data):
        response = requests.post(f"{self.base_url}{endpoint}", json=data)
        response.raise_for_status()
        
        result = response.json()
        if not result["success"]:
            raise Exception(result["error"])
        
        return result["data"]
    
    def get_key_derivation_signature(self, keypair: Keypair) -> str:
        message = f"Confidential Transfer Key Derivation: {keypair.public_key}"
        signature = keypair.sign(message.encode())
        return base64.b64encode(signature).decode()
    
    def setup_account(self, keypair: Keypair, mint_address: str):
        signature = self.get_key_derivation_signature(keypair)
        
        return self._call_api("/setup-account", {
            "owner_pubkey": str(keypair.public_key),
            "signature": signature,
            "mint_address": mint_address
        })
    
    def get_balance(self, keypair: Keypair, mint_address: str):
        signature = self.get_key_derivation_signature(keypair)
        
        return self._call_api("/balance", {
            "owner_pubkey": str(keypair.public_key),
            "signature": signature,
            "mint_address": mint_address
        })
    
    def deposit(self, keypair: Keypair, amount: int, mint_address: str):
        signature = self.get_key_derivation_signature(keypair)
        
        return self._call_api("/deposit", {
            "owner_pubkey": str(keypair.public_key),
            "signature": signature,
            "amount": amount,
            "mint_address": mint_address
        })

# Usage example
api = ConfidentialTransferAPI()
keypair = Keypair.generate()  # Or load your keypair
mint_address = "your_token_mint_address"

# Setup account
setup_response = api.setup_account(keypair, mint_address)
print(f"Setup transaction: {setup_response['transaction']}")

# Get balance
balance = api.get_balance(keypair, mint_address)
print(f"Available: {balance['available_balance']}")
print(f"Pending: {balance['pending_balance']}")

Security Considerations

1. Key Management

  • The API uses deterministic key derivation from wallet signatures

  • Private keys are never transmitted or stored

  • Each wallet generates unique encryption keys per token account

2. Transaction Security

  • All transactions are generated server-side but signed client-side

  • Users maintain full control of their wallets and funds

  • Zero-knowledge proofs ensure transaction privacy

3. Network Security

  • API uses HTTPS for all communications

  • CORS is properly configured for web applications

  • Rate limiting and DDoS protection are in place

4. Best Practices

  • Always verify transaction contents before signing

  • Use secure RPC endpoints for transaction submission

  • Implement proper error handling and user feedback

  • Store sensitive data securely on the client side


Note: This API is in active development. Breaking changes may occur in future versions. Please check this documentation regularly for updates.

PreviousCookbook

Last updated 8 days ago

📶
👨‍🔧