Integration Guide

Complete guide to integrating Inkognito Network into your application.

Overview

This guide covers:

  1. Setting up the client
  2. Managing commitments
  3. Handling 402 responses
  4. Making RPC calls
  5. Error handling
  6. Best practices

Prerequisites

Complete Example
1npm install @inkognito/client @solana/web3.js

Step 1: Generate and Store Commitments

Commitments are the foundation of privacy in Inkognito Network.

Generate a Commitment

Complete Example
1import { ZKProofGenerator } from '@inkognito/client';
2
3// Generate a random 254-bit commitment
4const commitment = ZKProofGenerator.generateRandomCommitment();
5
6console.log('Commitment:', commitment.toString());
7// Output: 12345678901234567890123456789012345678901234567890

Store Commitments Securely

For Web Applications:

Complete Example
1// Store in encrypted localStorage
2import { encrypt, decrypt } from 'your-encryption-lib';
3
4const userPassword = 'user-password';
5const encryptedCommitment = encrypt(commitment.toString(), userPassword);
6localStorage.setItem('inkognito_commitment', encryptedCommitment);
7
8// Retrieve later
9const stored = localStorage.getItem('inkognito_commitment');
10const decryptedCommitment = decrypt(stored, userPassword);

For Server Applications:

Complete Example
1// Store in environment variables or secrets manager
2process.env.INKOGNITO_COMMITMENT = commitment.toString();
3
4// Or use a secrets manager
5await secretsManager.setSecret('inkognito_commitment', commitment.toString());

For Mobile Applications:

Complete Example
1// Use secure storage
2import * as SecureStore from 'expo-secure-store';
3
4await SecureStore.setItemAsync('inkognito_commitment', commitment.toString());

Step 2: Initialize the Client

Complete Example
1import { InkognitoClient } from '@inkognito/client';
2
3// Basic initialization
4const client = new InkognitoClient({
5  endpoint: 'https://rpc.inkognito.network',
6  mode: 'zk',
7  commitment: commitment,
8  wasmPath: './circuits/payment_proof.wasm',
9  zkeyPath: './circuits/payment_proof_final.zkey',
10});
11
12// With custom configuration
13const client = new InkognitoClient({
14  endpoint: 'https://rpc.inkognito.network',
15  mode: 'zk',
16  commitment: commitment,
17  counter: 0, // Counter for nullifier generation
18  autoRetry: true, // Auto-retry failed requests
19  maxRetries: 3,
20  timeout: 30000, // 30 second timeout
21  wasmPath: 'https://cdn.inkognito.network/circuits/payment_proof.wasm',
22  zkeyPath: 'https://cdn.inkognito.network/circuits/payment_proof_final.zkey',
23});

Step 3: Handle 402 Payment Required

When you make a request without credits, you'll receive a 402 response.

Automatic Handling

Complete Example
1try {
2  const result = await client.request('getBalance', [address]);
3  console.log('Balance:', result);
4} catch (error) {
5  if (error.name === 'PaymentRequiredError') {
6    // Show payment UI to user
7    const invoice = error.invoice;
8
9    console.log('Payment required!');
10    console.log('Amount:', invoice.amount / 1e9, 'SOL');
11    console.log('Recipient:', invoice.recipient);
12    console.log('Expires:', new Date(invoice.expires_at * 1000));
13
14    // Redirect user to buy credits
15    window.location.href = `https://inkognito.network/playground?invoice=${invoice.invoice_id}`;
16  }
17}

Custom Payment UI

Complete Example
1import { Connection, PublicKey, Transaction, SystemProgram } from '@solana/web3.js';
2
3async function buyCredits(
4  commitment: bigint,
5  amount: number, // in SOL
6  wallet: any // Phantom/Solflare wallet
7) {
8  const connection = new Connection('https://api.devnet.solana.com');
9
10  // 1. Calculate commitment hash
11  const poseidon = await buildPoseidon();
12  const commitmentHash = poseidon.F.toString(poseidon([commitment]));
13
14  // 2. Convert to bytes
15  const hashBigInt = BigInt(commitmentHash);
16  const hashBytes = new Uint8Array(32);
17  for (let i = 0; i < 32; i++) {
18    hashBytes[i] = Number((hashBigInt >> BigInt(i * 8)) & BigInt(0xff));
19  }
20
21  // 3. Build transaction
22  const PROGRAM_ID = new PublicKey('F7hoT4cMvyqBeTrBEknkf2QkUBezRCqHJWDEn8xpyVs9');
23
24  // Derive PDA
25  const [creditAccount] = await PublicKey.findProgramAddress(
26    [Buffer.from('credit'), Buffer.from(hashBytes)],
27    PROGRAM_ID
28  );
29
30  const [treasury] = await PublicKey.findProgramAddress(
31    [Buffer.from('treasury')],
32    PROGRAM_ID
33  );
34
35  // Build instruction
36  const discriminator = new Uint8Array([0xf2, 0x23, 0xc6, 0x89, 0x52, 0xe1, 0xf2, 0xb6]);
37
38  const amountLamports = BigInt(amount * 1e9);
39  const amountBytes = new Uint8Array(8);
40  for (let i = 0; i < 8; i++) {
41    amountBytes[i] = Number((amountLamports >> BigInt(i * 8)) & BigInt(0xff));
42  }
43
44  const instructionData = new Uint8Array([
45    ...discriminator,
46    ...hashBytes,
47    ...amountBytes,
48  ]);
49
50  const instruction = new TransactionInstruction({
51    keys: [
52      { pubkey: wallet.publicKey, isSigner: true, isWritable: true },
53      { pubkey: creditAccount, isSigner: false, isWritable: true },
54      { pubkey: treasury, isSigner: false, isWritable: true },
55      { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
56    ],
57    programId: PROGRAM_ID,
58    data: Buffer.from(instructionData),
59  });
60
61  const transaction = new Transaction().add(instruction);
62  const signature = await wallet.sendTransaction(transaction, connection);
63
64  await connection.confirmTransaction(signature);
65
66  return signature;
67}

Step 4: Make RPC Calls

Standard Solana RPC Methods

Complete Example
1// Get block height
2const height = await client.request('getBlockHeight');
3
4// Get balance
5const balance = await client.request('getBalance', [address]);
6
7// Get account info
8const accountInfo = await client.request('getAccountInfo', [address]);
9
10// Get transaction
11const tx = await client.request('getTransaction', [signature]);
12
13// Get signatures for address
14const sigs = await client.request('getSignaturesForAddress', [
15  address,
16  { limit: 10 }
17]);
18
19// Get latest blockhash
20const blockhash = await client.request('getLatestBlockhash');
21
22// Get slot
23const slot = await client.request('getSlot');
24
25// Get version
26const version = await client.request('getVersion');

Batch Requests

Complete Example
1// Make multiple requests efficiently
2const results = await Promise.all([
3  client.request('getBlockHeight'),
4  client.request('getSlot'),
5  client.request('getVersion'),
6]);
7
8console.log('Height:', results[0]);
9console.log('Slot:', results[1]);
10console.log('Version:', results[2]);

Step 5: Error Handling

Complete Example
1import {
2  PaymentRequiredError,
3  InvalidSessionError,
4  RateLimitError,
5  InkognitoError,
6} from '@inkognito/client';
7
8async function makeRequest() {
9  try {
10    const result = await client.request('getBalance', [address]);
11    return result;
12  } catch (error) {
13    if (error instanceof PaymentRequiredError) {
14      // Need to buy credits
15      console.log('Buy credits:', error.invoice);
16      // Show payment UI
17    } else if (error instanceof InvalidSessionError) {
18      // Session expired, create new one
19      await client.createSession();
20      // Retry request
21      return makeRequest();
22    } else if (error instanceof RateLimitError) {
23      // Rate limited
24      console.log('Rate limited, retry after:', error.retryAfter);
25      await new Promise(resolve => setTimeout(resolve, error.retryAfter * 1000));
26      return makeRequest();
27    } else if (error instanceof InkognitoError) {
28      // General error
29      console.error('Inkognito error:', error.message);
30      console.error('Code:', error.code);
31      console.error('Data:', error.data);
32    } else {
33      // Unknown error
34      console.error('Unknown error:', error);
35    }
36  }
37}

Step 6: Session Management

Check Session Status

Complete Example
1// Get current session
2const session = client.getSession();
3
4if (session) {
5  console.log('Token:', session.token);
6  console.log('Requests remaining:', session.requestsRemaining);
7  console.log('Expires at:', new Date(session.expiresAt * 1000));
8  console.log('Nullifier:', session.nullifier); // ZK mode only
9}
10
11// Check if expired
12if (client.isSessionExpired()) {
13  await client.createSession();
14}

Clear Session

Complete Example
1// Clear current session
2client.clearSession();
3
4// Create new session
5await client.createSession();

Complete Example: React Hook

Complete Example
1import { useState, useEffect } from 'react';
2import { InkognitoClient, ZKProofGenerator } from '@inkognito/client';
3
4export function useInkognito() {
5  const [client, setClient] = useState<InkognitoClient | null>(null);
6  const [session, setSession] = useState(null);
7  const [loading, setLoading] = useState(true);
8  const [error, setError] = useState<string | null>(null);
9
10  useEffect(() => {
11    async function init() {
12      try {
13        // Get or generate commitment
14        let commitment = localStorage.getItem('inkognito_commitment');
15
16        if (!commitment) {
17          const newCommitment = ZKProofGenerator.generateRandomCommitment();
18          localStorage.setItem('inkognito_commitment', newCommitment.toString());
19          commitment = newCommitment.toString();
20        }
21
22        // Initialize client
23        const inkognitoClient = new InkognitoClient({
24          endpoint: 'https://rpc.inkognito.network',
25          mode: 'zk',
26          commitment: BigInt(commitment),
27          wasmPath: 'https://cdn.inkognito.network/circuits/payment_proof.wasm',
28          zkeyPath: 'https://cdn.inkognito.network/circuits/payment_proof_final.zkey',
29        });
30
31        setClient(inkognitoClient);
32        setLoading(false);
33      } catch (err: any) {
34        setError(err.message);
35        setLoading(false);
36      }
37    }
38
39    init();
40  }, []);
41
42  const request = async (method: string, params?: any[]) => {
43    if (!client) throw new Error('Client not initialized');
44
45    try {
46      const result = await client.request(method, params);
47      setSession(client.getSession());
48      return result;
49    } catch (err: any) {
50      if (err.name === 'PaymentRequiredError') {
51        // Handle payment required
52        throw err;
53      }
54      throw err;
55    }
56  };
57
58  return { client, session, loading, error, request };
59}
60
61// Usage in component
62function MyComponent() {
63  const { request, session, loading } = useInkognito();
64
65  const checkBalance = async (address: string) => {
66    try {
67      const balance = await request('getBalance', [address]);
68      console.log('Balance:', balance);
69    } catch (error) {
70      console.error('Error:', error);
71    }
72  };
73
74  if (loading) return <div>Loading...</div>;
75
76  return (
77    <div>
78      <p>Requests remaining: {session?.requestsRemaining}</p>
79      <button onClick={() => checkBalance('YOUR_ADDRESS')}>
80        Check Balance
81      </button>
82    </div>
83  );
84}

Best Practices

1. Commitment Management

DO: Generate unique commitments per application ✅ DO: Store commitments securely (encrypted storage) ✅ DO: Back up commitments (users can't recover credits without them) ❌ DON'T: Reuse commitments across different apps ❌ DON'T: Store commitments in plain text ❌ DON'T: Share commitments

2. Session Management

DO: Check session expiry before requests ✅ DO: Handle session refresh automatically ✅ DO: Monitor requests remaining ❌ DON'T: Create unnecessary sessions ❌ DON'T: Let sessions expire mid-operation

3. Error Handling

DO: Implement retry logic for network errors ✅ DO: Show clear error messages to users ✅ DO: Log errors for debugging ❌ DON'T: Expose sensitive error details to users ❌ DON'T: Retry on 402 (need to buy credits first)

4. Privacy

DO: Use Tor or VPN for maximum privacy ✅ DO: Generate new commitments periodically ✅ DO: Use different commitments for different use cases ❌ DON'T: Reuse deposit wallets for transactions ❌ DON'T: Link your Inkognito activity to other services

Next Steps