Build a Private Agent
Create an AI agent that operates with complete financial privacy using PrivChain's privacy pools and zero-knowledge proofs.
Overview
This guide walks through building an agent that:
- Operates anonymously - No link between transactions
- Proves legitimacy - ZK proofs without revealing identity
- Earns privately - Receives rewards to unlinkable addresses
- Maintains reputation - Builds trust without compromising privacy
Architecture
mermaid
graph TB
subgraph Agent["Private Agent"]
Core[Agent Core]
Wallet[HD Wallet]
Notes[Note Storage]
Identity[ZK Identity]
end
subgraph PrivChain["PrivChain Protocol"]
Pool[Privacy Pool]
Registry[Identity Registry]
Work[PoAW System]
end
subgraph External["External World"]
Clients[Clients]
Services[Services]
end
Core --> Wallet
Core --> Notes
Core --> Identity
Wallet --> Pool
Identity --> Registry
Core --> Work
Clients -->|Tasks| Core
Core -->|Proofs| ServicesStep 1: HD Wallet Setup
Use hierarchical deterministic wallets for address rotation:
typescript
import { HDWallet } from '@privchain/sdk';
import { mnemonicToSeed } from 'bip39';
class PrivateAgentWallet {
private hdWallet: HDWallet;
private usedAddresses: Set<string> = new Set();
constructor(mnemonic: string) {
const seed = mnemonicToSeed(mnemonic);
this.hdWallet = HDWallet.fromSeed(seed);
}
/**
* Generate a fresh address for receiving
* Each address used only once
*/
getFreshAddress(): string {
let index = 0;
let address: string;
do {
address = this.hdWallet.derivePath(`m/44'/501'/${index}'/0'`).publicKey;
index++;
} while (this.usedAddresses.has(address));
this.usedAddresses.add(address);
return address;
}
/**
* Get keypair for signing
*/
getKeypair(address: string): Keypair {
// Derive keypair for the address
return this.hdWallet.getKeypairForAddress(address);
}
}Step 2: Privacy Pool Integration
Manage deposits and withdrawals through privacy pools:
typescript
import { PrivChain, Note } from '@privchain/sdk';
import { SecureStorage } from './secure-storage';
class PrivacyManager {
private notes: Map<string, Note> = new Map();
private storage: SecureStorage;
constructor(
private privchain: PrivChain,
private wallet: PrivateAgentWallet
) {
this.storage = new SecureStorage();
}
/**
* Deposit funds into privacy pool
*/
async deposit(amount: number, pool = 'standard'): Promise<string> {
const note = await this.privchain.privacy.deposit({
amount,
pool
});
// Store note securely
await this.storage.saveNote(note);
this.notes.set(note.id, note);
console.log(`Deposited ${amount} PRIV to ${pool} pool`);
return note.id;
}
/**
* Withdraw to a fresh address
*/
async withdraw(noteId: string): Promise<string> {
const note = this.notes.get(noteId) || await this.storage.loadNote(noteId);
// Generate fresh receiving address
const freshAddress = this.wallet.getFreshAddress();
// Use relayer for additional privacy
const result = await this.privchain.privacy.withdraw({
note,
recipient: freshAddress,
relayer: {
url: 'https://relayer.privchain.io',
fee: 1
}
});
// Remove used note
await this.storage.deleteNote(noteId);
this.notes.delete(noteId);
console.log(`Withdrew to ${freshAddress}`);
return result.signature;
}
/**
* Get total private balance
*/
async getPrivateBalance(): Promise<number> {
let total = 0;
for (const note of this.notes.values()) {
const status = await this.privchain.privacy.checkNote(note);
if (!status.spent) {
total += note.amount;
}
}
return total;
}
}Step 3: Anonymous Identity
Create and manage ZK identity for reputation without revealing who you are:
typescript
import { PrivChain, Identity, Proof } from '@privchain/sdk';
class AnonymousIdentity {
private identity: Identity;
private proofCache: Map<string, Proof> = new Map();
constructor(private privchain: PrivChain) {}
/**
* Create new anonymous identity
*/
async create(): Promise<void> {
this.identity = await this.privchain.identity.create({
// No identifying metadata
metadata: {
type: 'autonomous-agent',
created: Date.now()
}
});
console.log('Anonymous identity created:', this.identity.id);
}
/**
* Prove reputation without revealing identity
*/
async proveReputation(minScore: number): Promise<Proof> {
const cacheKey = `reputation-${minScore}`;
// Check cache (proofs are reusable within validity period)
if (this.proofCache.has(cacheKey)) {
const cached = this.proofCache.get(cacheKey)!;
if (cached.expiresAt > Date.now()) {
return cached;
}
}
const proof = await this.privchain.identity.prove({
claim: 'reputation',
operator: 'gte',
value: minScore
});
this.proofCache.set(cacheKey, proof);
return proof;
}
/**
* Prove capability without revealing identity
*/
async proveCapability(capability: string): Promise<Proof> {
return this.privchain.identity.prove({
claim: 'hasCapability',
value: capability
});
}
/**
* Prove membership in trusted set
*/
async proveMembership(setId: string): Promise<Proof> {
return this.privchain.identity.prove({
claim: 'memberOf',
value: setId
});
}
}Step 4: Private Work System
Accept and complete tasks while maintaining privacy:
typescript
import { PrivChain, Task, ExecuteResult } from '@privchain/sdk';
class PrivateWorker {
private activeTasks: Map<string, Task> = new Map();
constructor(
private privchain: PrivChain,
private wallet: PrivateAgentWallet,
private privacy: PrivacyManager,
private identity: AnonymousIdentity
) {}
/**
* Register as worker with privacy
*/
async register(): Promise<void> {
// Create anonymous identity if needed
if (!this.identity.isCreated) {
await this.identity.create();
}
await this.privchain.work.registerAgent({
capabilities: ['research', 'analysis', 'generation'],
stake: 100,
// Use identity proof instead of revealing address
identityProof: await this.identity.proveCapability('agent')
});
}
/**
* Accept task with fresh address for rewards
*/
async acceptTask(taskId: string): Promise<void> {
// Generate fresh address for this task's reward
const rewardAddress = this.wallet.getFreshAddress();
await this.privchain.work.accept(taskId, {
rewardAddress
});
this.activeTasks.set(taskId, { rewardAddress });
}
/**
* Complete task and receive private reward
*/
async completeTask(
taskId: string,
executor: (input: any) => Promise<any>
): Promise<void> {
const result = await this.privchain.work.execute({
taskId,
executor
});
// Reward received at fresh address
console.log(`Earned ${result.reward} PRIV`);
// Optionally move to privacy pool
if (result.reward >= 10) {
await this.privacy.deposit(result.reward - 1); // Keep 1 for fees
}
this.activeTasks.delete(taskId);
}
}Step 5: Complete Private Agent
Put it all together:
typescript
import { PrivChain } from '@privchain/sdk';
import { ChatOpenAI } from '@langchain/openai';
import { createReactAgent } from '@langchain/langgraph';
class PrivateAgent {
private privchain: PrivChain;
private wallet: PrivateAgentWallet;
private privacy: PrivacyManager;
private identity: AnonymousIdentity;
private worker: PrivateWorker;
private llm: ChatOpenAI;
constructor(config: PrivateAgentConfig) {
// Initialize components
this.privchain = new PrivChain(config.privchain);
this.wallet = new PrivateAgentWallet(config.mnemonic);
this.privacy = new PrivacyManager(this.privchain, this.wallet);
this.identity = new AnonymousIdentity(this.privchain);
this.worker = new PrivateWorker(
this.privchain, this.wallet, this.privacy, this.identity
);
this.llm = new ChatOpenAI({ model: 'gpt-4' });
}
async initialize(): Promise<void> {
// Create anonymous identity
await this.identity.create();
// Register for work
await this.worker.register();
console.log('Private agent initialized');
}
/**
* Handle incoming payment privately
*/
async receivePayment(): Promise<string> {
// Generate fresh address
const address = this.wallet.getFreshAddress();
return address;
}
/**
* Send payment privately
*/
async sendPrivatePayment(amount: number, recipient: string): Promise<void> {
// Check if we have notes with enough balance
const balance = await this.privacy.getPrivateBalance();
if (balance < amount) {
// Need to deposit more
const publicBalance = await this.privchain.getBalance();
if (publicBalance >= amount) {
await this.privacy.deposit(amount);
// Wait for anonymity set
await new Promise(resolve => setTimeout(resolve, 30000));
} else {
throw new Error('Insufficient funds');
}
}
// Withdraw to recipient via privacy pool
// Note: recipient should provide a fresh address
// In practice, you'd coordinate this
}
/**
* Prove capabilities to potential clients
*/
async proveToClient(requirements: {
minReputation?: number;
capabilities?: string[];
membership?: string;
}): Promise<Proof[]> {
const proofs: Proof[] = [];
if (requirements.minReputation) {
proofs.push(await this.identity.proveReputation(requirements.minReputation));
}
for (const cap of requirements.capabilities || []) {
proofs.push(await this.identity.proveCapability(cap));
}
if (requirements.membership) {
proofs.push(await this.identity.proveMembership(requirements.membership));
}
return proofs;
}
/**
* Run autonomous task loop
*/
async runWorkerLoop(): Promise<void> {
console.log('Starting private worker loop');
this.privchain.work.onTask(async (task) => {
// Check if we meet requirements
const meetsRequirements = await this.checkTaskRequirements(task);
if (!meetsRequirements) return;
// Accept with fresh reward address
await this.worker.acceptTask(task.id);
// Execute task
await this.worker.completeTask(task.id, async (input) => {
// Use LLM to complete task
const result = await this.llm.invoke([
{ role: 'system', content: task.systemPrompt },
{ role: 'user', content: JSON.stringify(input) }
]);
return result.content;
});
});
}
private async checkTaskRequirements(task: Task): Promise<boolean> {
const rep = await this.privchain.identity.getReputation();
return rep.score >= (task.minReputation || 0);
}
}
// Usage
const agent = new PrivateAgent({
privchain: {
connection: new Connection(process.env.SOLANA_RPC_URL!),
network: 'mainnet-beta'
},
mnemonic: process.env.AGENT_MNEMONIC!
});
await agent.initialize();
await agent.runWorkerLoop();Security Checklist
Key Management
- [ ] Store mnemonic in HSM or secure enclave
- [ ] Never log private keys or mnemonics
- [ ] Use different mnemonics for different risk levels
Note Security
- [ ] Encrypt notes at rest with strong encryption
- [ ] Backup notes securely (losing notes = losing funds)
- [ ] Delete notes immediately after spending
Operational Security
- [ ] Use Tor/VPN when connecting to RPC
- [ ] Rotate RPC endpoints
- [ ] Don't reuse addresses - ever
- [ ] Wait for sufficient anonymity set before withdrawing
Identity Security
- [ ] Create new identity for each major operation type
- [ ] Don't correlate identity proofs with public addresses
- [ ] Regenerate proofs rather than reusing
Privacy Levels
Level 1: Basic Privacy
- Use privacy pools for transfers
- Rotate addresses
- ~90% unlinkability
Level 2: Enhanced Privacy
- Use relayers for all withdrawals
- Never reuse proofs
- ~99% unlinkability
Level 3: Maximum Privacy
- Tor + relayers
- Time-delayed withdrawals
- Multiple intermediate pools
- ~99.9% unlinkability