Skip to main content

On-chain program

The Enclz program is an Anchor-based Solana smart contract written in Rust. It's the source of truth for every spend policy.

  • Source: enclz/solana
  • Program ID: read dynamically from @enclz/sdk — don't hardcode (it changes between devnet and mainnet).
  • Anchor IDL: published on-chain and accessible via Program.fetchIdl().

What lives on-chain

AccountSeedPurpose
GroupConfig["group", owner_pubkey]Per-orchestrator group config — name, owner, fee recipient, DEX router
AgentWallet["agent", group, agent_pubkey]Per-agent state — limits, counters, nonce, owner
WhitelistEntry["whitelist", group, target_address]Per-recipient authorization — type, TTL, amount cap, amount used

Token accounts (ATAs) for each agent are owned by the AgentWallet PDA and created at agent initialization.

What does not live on-chain

  • Agent API keys — bcrypt-hashed in the backend's database.
  • Audit memos (the human-readable strings attached to transfers) — stored in the backend log; the on-chain memo field is a fixed-length 32-byte hash.
  • Webhook subscriptions — backend-only.
  • Orchestrator session JWTs — issued by the backend after SIWS verification, never written to chain.

The split is deliberate: anything that affects who-can-spend-what lives on-chain. Anything that's a notification convenience or a credential lives off-chain.

Read paths

The webapp and the backend both read on-chain state via Anchor:

  • getGroupConfig(group_pda) — fetches a group's config.
  • getAgentWallet(agent_wallet_pda) — fetches an agent's policy + counters.
  • listAgentsForGroup(group_pda) — enumerates all agents in a group.
  • listWhitelistEntries(group_pda) — enumerates all whitelist entries for a group.

The webapp uses these for the dashboard. Anyone with a Solana RPC can run the same reads directly without going through the webapp or the backend.

Write paths

Every mutation goes through one of the program's instructions. See Instructions for the full list. Mutations split into two camps:

  • Owner-signed (the orchestrator's wallet must sign): initialize_group, add_agent, add_to_whitelist, renew_whitelist_entry, remove_from_whitelist, update_agent_limits, update_backend_operator, emergency_withdraw.
  • Operator-signed (the backend's operator keypair signs): execute_transfer, execute_swap, execute_deposit, execute_withdraw. The backend signs as the agent's executor — but every check happens in the program, so the backend cannot grant the agent any authority the program doesn't already permit.

Why an on-chain program

The on-chain enforcement is the differentiator. Several alternatives exist:

AlternativeWhere the policy livesWhat happens if compromised
Plain hot walletNowhereDrained immediately
Backend-enforced limitsBackend databaseDrained when backend is compromised
Multi-sigOff-chain coordinationLimits are not enforced on-chain — only signing thresholds are
EnclzOn-chain Anchor programPolicy holds; attacker bounded by per-tx and daily caps and whitelist

The trust assumption with Enclz reduces to: the on-chain program is correct. That's auditable, freezable (program upgrades require keypair the team holds, with future plans to relinquish), and verifiable per-instruction on Solana Explorer.