Skip to main content

What is a policy?

A policy is a gateway-canonical set of rules that the guard engine evaluates against an incoming transaction intent. It binds to a specific policyId and chainId — no single policy spans multiple chains. Every mutation of the rules set creates a new immutable snapshot (incremented version). The policyHash is a deterministic keccak256(JCS(body)) fingerprint of the policy body at that version.

Policy shape

All string values are decimal-encoded (not hex) for JSON interoperability. allowedTargets are stored and compared lowercased.

Policy hash

The policyHash is computed by:
  1. Strip ephemeral fields (owner, createdAt, updatedAt, metadata)
  2. Lowercase all entries in allowedTargets
  3. Serialize with JCS (RFC 8785) — canonical JSON
  4. Hash with keccak256(utf8(jcs_string))
You can compute it locally (for offline verification) or server-side:
Both must return the same hash. A mismatch indicates a bug.

Guard rules engine

Evaluation order: target → selector → value → daily cap → simulation → threshold.
maxSlippageBps is not enforced in v0.2. The field is stored in the policy body and included in the policyHash, but the guard engine does not evaluate it. Pilots setting maxSlippageBps should treat it as a label for future enforcement (planned v0.3). Transactions will not be denied based on slippage in the current release.
dailyCapWei uses a rolling 24-hour window, not a calendar day. The cap counts executed + anchored transactions in the last 86,400 seconds from the current timestamp — not from midnight UTC. Compliance teams expecting a midnight reset should note this distinction. Calendar-day reset is planned as an opt-in flag in v0.3.
from address is not constrained in v0.2. Any address can submit a guard request for your policy. The policy rules constrain what the transaction can do (target, selector, value) — not which agent can request the guard. Per-caller allowlists (allowedCallers) are a v0.3 roadmap item.

CRUD

Policy State Machine

Every policy has a state field that follows a strict one-way progression:
revoked is irreversible. Once a policy is revoked, no new guard requests are accepted and verifyRemote() returns valid: false for all receipts issued under it. Use frozen for temporary suspension.

policySource field in receipts

Chain binding

A policy binds to exactly one chainId. If a guard request arrives with a different chainId than the policy’s, the gateway returns HTTP 400 CHAIN_MISMATCH.

PolicyAnchor — Security Notes

The PolicyAnchor contract is permissionless: any address can anchor any policyId string for any operator address. The first caller wins the policyKey = keccak256(operatorAddress, policyId, chainId).
Front-running mitigation: The AgentChain gateway anchors your policy key immediately on creation (best-effort, async). If the anchor call is delayed, a third party could theoretically claim your policyKey before the gateway does. This is a testnet-only risk — the gateway has SLA anchoring within 30 seconds of policy creation. For mainnet, EIP-712 signed anchor claims are planned (v0.3).
Anchoring does NOT affect guard enforcement — the gateway uses its database as the source of truth. PolicyAnchor is an audit log, not a policy registry.