Integration Guide
Complete guide to integrating Inkognito Network into your application.
Overview
This guide covers:
- Setting up the client
- Managing commitments
- Handling 402 responses
- Making RPC calls
- Error handling
- Best practices
Prerequisites
1npm install @inkognito/client @solana/web3.jsStep 1: Generate and Store Commitments
Commitments are the foundation of privacy in Inkognito Network.
Generate a Commitment
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: 12345678901234567890123456789012345678901234567890Store Commitments Securely
For Web Applications:
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:
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:
1// Use secure storage
2import * as SecureStore from 'expo-secure-store';
3
4await SecureStore.setItemAsync('inkognito_commitment', commitment.toString());Step 2: Initialize the Client
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
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
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
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
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
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
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
1// Clear current session
2client.clearSession();
3
4// Create new session
5await client.createSession();Complete Example: React Hook
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
- API Reference - All available methods
- Use Cases - Real-world examples
- Privacy Best Practices - Maximize privacy