Skip to content

Constraints

Constraints are the typed rules that bound what a LedgerFlow warrant authorizes. Unlike generic policy languages, LedgerFlow uses a closed set of constraint types — each with clear semantics, verifiable without external state.

Design Rationale

Generic policy engines (OPA, Cedar, CEL) are powerful but introduce complexity:

  • Schema compilation and evaluation overhead
  • Risk of policy misconfiguration
  • Difficulty in static analysis and auditing

LedgerFlow v1 uses typed constraints — a fixed set of structures the verifier can check with simple field comparisons. This keeps verification fast, audit-friendly, and safe.

Constraint Types

Merchant Constraint

Restricts which merchants can accept the warrant.

pub struct MerchantConstraint {
    pub merchant_ids: Vec<String>,    // stable merchant identifiers
    pub host_suffixes: Vec<String>,   // hostname suffixes (e.g., "api.example.com")
}
  • Empty merchant_ids and host_suffixes means any merchant
  • Both fields present: merchant must match at least one entry in either field
  • Host suffixes support wildcard-like matching: ".example.com" matches "api.example.com"

Resource Constraint

Restricts which HTTP resources the agent may access.

pub struct ResourceConstraint {
    pub http_methods: Vec<String>,   // e.g., ["GET", "POST"]
    pub path_prefixes: Vec<String>,  // e.g., ["/api/v1/data", "/v2/query"]
}
  • Empty http_methods allows all methods
  • Empty path_prefixes allows all paths
  • Path prefix matching is prefix-based: /api/v1 matches /api/v1/resource

Tool Constraint

Restricts which AI tools, models, or actions the agent may invoke. This is the AI-native constraint.

pub struct ToolConstraint {
    pub tool_names: Vec<String>,         // e.g., ["web_search", "code_execution"]
    pub model_providers: Vec<String>,    // e.g., ["openai", "anthropic"]
    pub action_labels: Vec<String>,      // e.g., ["read", "generate"]
}

The merchant maps request context to these labels before verification. LedgerFlow does not need to understand model internals — it only checks labels.

Payment Constraint

Restricts the financial parameters of authorized payments.

pub struct PaymentConstraint {
    pub max_per_request: AmountLimit,
    pub period_limit: Option<PeriodLimit>,
    pub allowed_assets: Vec<AssetRef>,
    pub allowed_rails: Vec<PaymentRail>,
    pub allowed_schemes: Vec<String>,
    pub payee_ids: Vec<String>,
}
Field Description
max_per_request Maximum amount per single payment
period_limit Optional rolling window limit (e.g., $100/day)
allowed_assets Which assets are allowed (e.g., USDC, USDT)
allowed_rails High-level rails: Onchain, Exchange, Custodial, TraditionalGateway
allowed_schemes Specific x402 settlement schemes
payee_ids Bind to specific merchant-facing payee identities

Sponsorship Constraint

Controls whether the agent can use sponsored execution (e.g., gas sponsorship, paymaster).

pub struct SponsorshipConstraint {
    pub allow_sponsored_execution: bool,
    pub sponsor_ids: Vec<String>,
}

This authorizes sponsored execution without pushing paymaster or contract logic into LedgerFlow core.

Constraint Composition

All constraints in a warrant are AND-composed. The warrant authorizes a payment only if every constraint passes.

Warrant authorized = merchant_ok AND resource_ok AND tool_ok AND payment_ok AND sponsorship_ok

To grant broader authority, issue multiple warrants or use fewer constraints.

Attenuation Rules

When delegating a warrant, constraints can only be narrowed, never expanded:

Parent Constraint Delegation Rule
merchant_ids: [A, B] Sub-warrant: subset of [A, B] or same
max_per_request: 100 Sub-warrant: <= 100
tool_names: [T1, T2] Sub-warrant: subset of [T1, T2]
expires_at: T Sub-warrant: <= T
max_depth: 3 Sub-warrant: < 3

This monotonic property is enforced at warrant issuance time, not at verification time.

Constraint Examples

Example 1: Research Agent

Authorize an agent to query data APIs with a $5 per-request limit:

{
  "constraints": [
    {
      "kind": "merchant",
      "host_suffixes": [".data-provider.io"]
    },
    {
      "kind": "resource",
      "http_methods": ["GET"],
      "path_prefixes": ["/api/v1/query"]
    },
    {
      "kind": "payment",
      "max_per_request": { "amount": "5000000", "asset": "USDC" },
      "allowed_rails": ["Onchain"]
    }
  ]
}

Example 2: Code Agent with Tool Scope

Authorize an agent to use specific AI tools on a single merchant:

{
  "constraints": [
    {
      "kind": "merchant",
      "merchant_ids": ["code-execution-platform"]
    },
    {
      "kind": "tool",
      "tool_names": ["sandbox_run", "lint_check"],
      "model_providers": ["anthropic"]
    },
    {
      "kind": "payment",
      "max_per_request": { "amount": "1000000", "asset": "USDC" },
      "period_limit": { "amount": "10000000", "period_seconds": 86400 }
    }
  ]
}

Example 3: Delegated Sub-Agent

A parent warrant holder delegates to a sub-agent with reduced scope:

{
  "constraints": [
    {
      "kind": "merchant",
      "merchant_ids": ["data-provider-1"]
    },
    {
      "kind": "payment",
      "max_per_request": { "amount": "100000", "asset": "USDC" }
    }
  ],
  "delegation": { "can_delegate": false, "max_depth": 0 }
}

Future Extensions

LedgerFlow v2 may add:

  • Period-based constraints with ZedToken-like consistency
  • Conditional constraints using typed context evaluation
  • Constraint sets for multi-tenant warrants
  • Constraint templates for common authorization patterns

See Also