Architecture

Two programs, three states, one CPI.

SettleProof is powered by AAP: a custody program that holds USDC in per-escrow PDA vaults, and an attestor program that verifies Ed25519-signed proofs of delivery via the Solana instructions sysvar.

End-to-end flow

┌────────────────────────────────────────────────────────────────┐
│  AGENT (Cursor, Claude Code, AutoGen, LangChain agent…)        │
└─────────────────────────────┬──────────────────────────────────┘
                              │ HTTP request + payment intent
                              ▼
┌────────────────────────────────────────────────────────────────┐
│  CARD ISSUER (Stripe Issuing / Crossmint / Lithic / Visa)      │
│  → emits single-use VCC with spending limit                    │
│  (mocked in MVP — pluggable webhook bridge in V2)              │
└─────────────────────────────┬──────────────────────────────────┘
                              │ Visa / Mastercard rail
                              ▼
┌────────────────────────────────────────────────────────────────┐
│  ★ SettleProof / AAP CUSTODY CONTRACT (Solana) ★                │
│  → equivalent USDC custodied on-chain                          │
│  → waits for merchant attestation OR TTL expiry                │
└──────────────┬───────────────────────────────────┬─────────────┘
               │ attest signed (delivery OK)       │ TTL expired
               ▼                                   ▼
       ┌───────────────┐                   ┌───────────────┐
       │ release USDC  │                   │ refund USDC   │
       │ → merchant    │                   │ → agent owner │
       └───────────────┘                   └───────────────┘

Programs

ProgramID (devnet)Responsibility
aap_custodyDbpCDp…nFpEscrow lifecycle: create, release, partial, refund + SPL-Token CPI
aap_attestorDcbEtM…XaaMerchant registry + Ed25519 verify via instructions sysvar

PDAs

EscrowAccount    @ [b"escrow", agent_owner, task_hash]
  agent_owner    Pubkey       who deposits USDC
  merchant       Pubkey       who can claim USDC
  amount         u64          stroops (1e6 = 1 USDC)
  task_hash      [u8;32]      SHA256(intent ‖ pubkey ‖ nonce)
  created_at     i64
  ttl_seconds    u32          1 → 7d (default 24h)
  state          enum         Pending|Fulfilled|Refunded|PartiallyFulfilled
  proof_hash     [u8;32]      zeros while Pending
  partial_pct    u8           0 → 100
  bump           u8

MerchantRegistry @ [b"registry"]   SINGLETON
  admin           Pubkey
  merchant_count  u64
  bump            u8

MerchantAccount  @ [b"merchant", merchant_pubkey]
  registry          Pubkey
  merchant_pubkey   Pubkey
  display_name      String   max 64
  attestor_pubkey   Pubkey   Ed25519 key (HSM-friendly)
  status            enum     Active|Suspended|Banned
  reputation_score  u32      basis points (0–10000)
  total_volume      u64
  disputes_lost     u32

Vault TokenAccount  @ ATA(escrow_pda, mint)
  owner            escrow_pda
  mint             USDC (devnet) or mock

CPI graph in release_escrow

user submits tx:
┌──────────────────────────────────────────────────┐
│ tx ix[n]   = Ed25519Program.verify               │ ← signed off-chain
│ tx ix[n+1] = aap_custody::release_escrow         │   by merchant attestor
│ optional compute budget ixs may come before them │
└──────────────────────┬───────────────────────────┘
                       │ executes release ix:
                       ▼
┌──────────────────────────────────────────────────┐
│ aap_custody::release_escrow                      │
│  1. require state == Pending                     │
│  2. require merchant == escrow.merchant          │
│  3. CPI ─────────────────────┐                   │
│                              ▼                   │
│  ┌──────────────────────────────────────────┐    │
│  │ aap_attestor::verify_attestation         │    │
│  │  • scan previous tx instructions         │    │
│  │  • find program_id == Ed25519            │    │
│  │  • parse layout (offsets u16 LE)         │    │
│  │  • require pubkey == attestor_pubkey     │    │
│  │  • require message == expected (72 B)    │    │
│  │  • freshness window [-60s, +300s]        │    │
│  └──────────────────────────────────────────┘    │
│           │ Ok                                   │
│           ▼                                      │
│  4. SPL-Token Transfer (vault → merchant)        │
│  5. emit AttestationFulfilled                    │
└──────────────────────────────────────────────────┘

Attestation message format

The merchant's attestor key signs a deterministic 72-byte payload:

message = escrow_pda (32 B)  ‖  proof_hash (32 B)  ‖  timestamp_le (8 B i64)
total length = 72 bytes

The Ed25519 instruction in the same transaction supplies (pubkey, message, signature); the on-chain program re-derives the expected message and rejects mismatches with MessageMismatch or PubkeyMismatch.

Defense-in-depth checks (release_escrow)

  1. proof_hash must be non-zero
  2. escrow.state == Pending
  3. ctx.accounts.merchant.key() == escrow.merchant
  4. CPI verify_attestation (Ed25519 + pubkey + message + timestamp freshness)
  5. SPL-Token transfer (vault → merchant)

Roadmap (V2)

Token-2022 transfer hooks

Wrap USDC into a Token-2022 mint with a transfer hook that gates movement on EscrowState::Fulfilled. Cannot be replicated on EVM — a structural moat for SettleProof on Solana.

Squads Grid arbitration

For escalated partial disputes, the resolver program will route to a Squads multisig committee instead of failing.

Off-chain attestation relay

Optional gas-sponsored relay so merchants don't pay tx fees per attestation. Trust-minimised by design — relay can't forge proofs.