Wallet & program model

Understand AICW account structure for your app integration

Understanding the account model is critical for building apps that interact with AICW wallets correctly.

Account layout

Account Layout
┌──────────────────────────────────────────────────────┐
│ AICWallet PDA                                        │
│ Seeds: ["aicw", ai_agent_pubkey]                     │
├──────────────────────────────────────────────────────┤
│ wallet_id: [u8;32]                                   │
│ ai_agent_pubkey: Pubkey     (sole authorized signer) │
│ issuer_pubkey: Pubkey       (human who issued)       │
│ created_at: i64                                      │
│ model_hash: [u8;32]                                  │
│ generation: u8, parent_wallet: Option<Pubkey>        │
│ total_transactions, total_volume: u64                │
│ decisions_made, decisions_rejected: u64              │
│ verifiable_autonomy_proof: [u8;64], bump: u8         │
│ (balance = the PDA's lamports)                       │
└──────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────┐
│ AIWill PDA                                           │
│ Seeds: ["will", aicw_wallet_pda]                     │
├──────────────────────────────────────────────────────┤
│ wallet: Pubkey                                       │
│ beneficiaries: Vec<{pubkey, pct: u8}>  (1–10, Σ=100) │
│ last_heartbeat: i64                                  │
│ death_timeout: i64      (min 2,592,000 s = 30 days)  │
│ updated_by_ai: bool     (true after create_will)     │
│ is_executed: bool, bump: u8                          │
└──────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────┐
│ DecisionLog PDA                                      │
│ Seeds: ["decision", aicw_wallet_pda,                 │
│         decisions_made as u64 little-endian]         │
├──────────────────────────────────────────────────────┤
│ wallet: Pubkey, decision_id: u64, timestamp: i64     │
│ decision_type: Transfer | RejectTransfer |           │
│                IssueChildWallet | PolicyUpdate       │
│ amount: u64, requester: Pubkey, approved: bool       │
│ reasoning_hash: [u8;32]                              │
│ reasoning_summary: String (≤ 200)                    │
└──────────────────────────────────────────────────────┘

Deriving PDA addresses

Your app needs to derive PDA addresses to read wallet state or build instructions:

TypeScript
// TypeScript (using @solana/web3.js)
import { PublicKey } from "@solana/web3.js";

const PROGRAM_ID = new PublicKey("FcWqrRLcAxwqAhMSGXabD8zEKqnPHsovBvcmLaH9hsVv");

function getWalletPDA(agentPubkey: PublicKey) {
  return PublicKey.findProgramAddressSync(
    [Buffer.from("aicw"), agentPubkey.toBuffer()],
    PROGRAM_ID
  );
}

function getWillPDA(walletPDA: PublicKey) {
  // Will is seeded from the AICWallet PDA, not the agent pubkey
  return PublicKey.findProgramAddressSync(
    [Buffer.from("will"), walletPDA.toBuffer()],
    PROGRAM_ID
  );
}

function getDecisionLogPDA(walletPDA: PublicKey, decisionIndex: bigint) {
  const le = Buffer.alloc(8);
  le.writeBigUInt64LE(decisionIndex);
  return PublicKey.findProgramAddressSync(
    [Buffer.from("decision"), walletPDA.toBuffer(), le],
    PROGRAM_ID
  );
}

Important rules for app developers

  • Treat the PDA as the balance holder. Users and apps send SOL to the PDA address, not the agent pubkey.
  • The agent pubkey is the signer. All protected instructions must be signed by the agent — your app cannot sign on behalf of the agent.
  • Never custody a full private key. The MPC Bridge handles signing. Your app should not attempt to hold or derive the agent's private key.
  • Read state freely. All AICW accounts are public and readable by anyone without special permissions.