AgentTrust
AgentTrust
ProgramsPolicyVault

PolicyVault

The decision engine — five orthogonal policy kinds composed under one gate_payment instruction with fail-fast semantics.

PolicyVault is the program that turns "should this payment go through?" into a typed GateDecision. It reads the payer agent, the payee agent, the policy account, the velocity ledger, the kill switch, the payer's AtomStats (Quantu), the payee's AtomStats, and an optional ValidationAttestation, then returns one of three values:

pub enum GateDecision {
    Allow,
    Deny(DenyReason),
    RequireValidation([u8; 32]),  // capability_hash
}

Devnet: 8Y6fGeNEHgmWmbt8JsRcF72jxbeBfJhomMjG6SuoJQTR

Instructions

InstructionEffect
init_authorityCreate PolicyAuthority PDA with multisig members + threshold
init_killswitchCreate KillSwitchState PDA (per-agent / per-collection / global)
init_policyCreate PolicyAccount + VelocityLedger for (agent, policy_id)
set_killswitchPause / unpause; multisig-gated against PolicyAuthority
gate_paymentLazy decision — returns Allow / Deny(reason) / RequireValidation(hash)
gate_payment_strictStrict variant — returns Ok(()) iff Allow, else Err. The SDK's atomic composer uses this.

The strict variant is the load-bearing one for atomicity. Phase J5 added a Kani proof, gate_payment_strict_correctness, that pins strict_returns_ok_iff_allow (a biconditional) and gate_decision_is_one_of_three_disjoint_variants. A future change that re-routes the Deny arm to an Ok return fails the proof loud.

State accounts

PDASeedsSizeRole
PolicyAuthority["policy_authority", agent_asset]272Multisig members + threshold (1..=7)
KillSwitchState["killswitch", scope_kind, scope_key]96Emergency pause flag + audit trail
PolicyAccount["policy", agent_asset, policy_id_le]240Per-policy config + lazy counters
VelocityLedger["velocity", agent_asset, policy_id_le]80Sliding-window cumulative-spend counter

Per-program byte layouts live on each policy page (linked below). The full PolicyAccount declaration is in programs/policy-vault/src/state/policy_account.rs.

The composer

gate_payment is a thin Anchor wrapper around the pure-Rust compose_decision function. The wrapper:

  1. Snapshots all read accounts into plain Rust structs (PolicySnapshot, VelocityLedgerSnapshot, KillSwitchSnapshot, optional AtomStatsView ×2, optional ValidationAttestationView).
  2. Calls compose_decision(input).
  3. On Allow, applies the returned SpendingDeltas and VelocityDeltas to PolicyAccount and VelocityLedger respectively.
  4. On Deny or RequireValidation, mutates nothing.

Order is fixed and fail-fast:

#PolicyCostFails fast on
1KillSwitchcheapest (one bool)paused == true
2Spendingpure arithmeticper-tx / daily / weekly limits
3Velocityone PDA readsliding-window cap
4CounterpartyTiertwo AtomStats PDA readstier / risk / confidence
5RequireValidationone attestation PDA readsubject / capability / expiry / attestor

Full composer reference: Composer.

DenyReason codes

DenyReason is the enum returned in the Deny arm. The Borsh wire format follows declaration order, but clients should consume the stable numeric code() instead — it is decoupled from Borsh field order.

CodeVariantOriginating policy
1KillSwitchEngagedKillSwitch
2SpendingPerTxExceededSpending
3SpendingDailyExceededSpending
4SpendingWeeklyExceededSpending
5VelocityWindowExceededVelocity
6CounterpartyTierBelowMinCounterpartyTier
7CounterpartyRiskAboveMaxCounterpartyTier
8CounterpartyConfidenceBelowCounterpartyTier
9AtomStatsWrongOwnerCounterpartyTier (defensive)
10AtomStatsSchemaMismatchCounterpartyTier (defensive)
11AttestationMissingRequireValidation
12AttestationExpiredRequireValidation
13AttestationRevokedRequireValidation
14AttestationAttestorRejectedRequireValidation
15UnratedTreatmentDenyCounterpartyTier (Unrated → Deny resolution)

Full table with remediation hints: Reference → DenyReason codes.

Formal verification

7 / 7 invariants formally verified

PolicyVault safety properties are machine-checked by Kani in CI — 662 sub-checks, zero failures.

  • paused_implies_no_allow
  • velocity_counter_le_limit
  • counterparty_tier_monotone
  • validation_expiry_correct
  • multisig_threshold_enforced
  • gate_payment_strict_correctness
  • spending_allow_respects_caps

Seven Kani harnesses run on every PR via .github/workflows/kani-prove.yml. Per-harness deep-dive: Verification → Kani proofs.

Source

On this page

⌘I