Skip to content
MANDATE owl logoMANDATE

Verifiable Policy Controls for Autonomous Financial Agents

Give agents authority.
Not unlimited authority.

MANDATE sits between an AI agent and financial execution. Every action must prove that it complies with the user's predefined policy before it can reach the execution layer.

Local MVP · Experimental · Not Audited
MANDATE owl logo

The problem

Agents need authority, but not unlimited authority

AI agents are increasingly able to place trades, initiate payments, manage portfolio positions, and interact with protocols directly. Prompt instructions, backend permissions, and human approvals alone are not enough — enforcement happens at a layer the agent can influence, that a third party cannot independently verify, or that requires trusting a centralized operator.

RiskExampleWithout MANDATE
Prompt injectionMalicious input instructs agent to place an oversized orderInstruction may override original policy
Strategy bugAgent miscalculates position and submits an oversized tradeNo circuit-level constraint
Unauthorized marketAgent selects an asset not on the approved listNo enforceable whitelist
Policy manipulationLocal execution limits differ from registered policyNo on-chain commitment to verify against
Compromised runtimeAgent output is tampered with before submissionNo cryptographic receipt of compliance
State inconsistencyOff-chain portfolio data is stale or falsifiedNo state-root verification

Key insight

There is a difference between asking an agent not to exceed a limit and making it mathematically impossible for the agent to submit an action that does.

Definition

What MANDATE is

A verifiable policy layer placed between an AI agent and a financial execution rail. It takes a user-defined mandate, registers a cryptographic fingerprint of it on-chain, and requires every execution action to carry a zero-knowledge proof that it satisfies those rules.

MANDATE is

  • + Policy enforcement infrastructure
  • + An agent authorization layer
  • + A proof generation and verification path
  • + An integration layer for execution systems
  • + Verifiable delegated authority
  • + A protection layer for autonomous agents

MANDATE is not

  • An AI model or trading strategy
  • A general-purpose wallet
  • A replacement for MoonPay
  • A centralized risk API
  • A simple transaction simulator
  • A standard multi-signature scheme

Core principle

Prove the action, not the model. MANDATE does not prove that an AI is trustworthy. It proves that a specific proposed action satisfies a committed policy against an anchored portfolio state.

How it works

Five steps, one enforcement point

MANDATE allows the agent to act autonomously, but only inside a policy the agent cannot rewrite.

  1. User policy

  2. Policy commitment

  3. AI agent action

  4. MANDATE SDK

  5. ZK compliance proof

Valid proof

Contract verifies → order submitted to the batch auction.

Invalid proof

Proof cannot be generated → order rejected, nothing on-chain.

  1. 1 · User

    Define the mandate

    Approved markets, size limits, position caps, and loss limits — set once.

  2. 2 · MANDATE

    Register policy + session key

    A policy commitment is registered on-chain; the agent is issued a scoped session key.

  3. 3 · Agent

    Propose an order

    The agent decides an action based on its own logic or a user instruction.

  4. 4 · MANDATE

    Generate a compliance proof

    The order is checked against the policy; a valid proof is produced only if every constraint holds.

  5. 5 · System

    Execute — or reject

    Only orders accompanied by a valid proof are submitted to the batch auction.

Execution flow visualization

A visualization of the documented local MVP demo — not a live transaction simulator.

  1. Agent proposes order

  2. Check against policy

  3. Generate ZK compliance proof

  4. Submit to batch auction

Side
buy
Quantity
250
Limit price
3,500
Policy limit
1,000,000
Notional (qty × price)
875,000
Proof generated
Yes

Result

Submitted

Formula: order notional = quantity × limit price.

Architecture

From agent call to on-chain proof

The agent interacts only with the MCP server. Proof generation and on-chain commitment happen entirely inside the SDK and contract layer.

MoonPay Agent

user-facing

MANDATE MCP Server

3 tools only

MANDATE SDK

proves + submits

Noir Compliance Proof

Noir / UltraHonk

Registry Contract

policy + session key

Auction Contract

proof-gated, on-chain

MandateAccount

funds + escape hatch

Sequencer

epoch loop, state

Local Ethereum Chain

Anvil

The agent interacts only with the MCP server. Proof generation and on-chain commitment happen entirely inside the SDK and contract layer.

Security model

Defense in depth

Eight independent layers. Failure at any single layer is sufficient to prevent an order from being submitted.

  1. 1

    Schema validation

    Malformed inputs are rejected before any processing (Zod-validated MCP tool inputs).

  2. 2

    Session-key authorization

    The agent must hold a registered key scoped to a specific mandate. The session key has zero authority over funds — no MandateAccount function is callable by it.

  3. 3

    Policy-commitment verification

    MandateClient checks the local plaintext policy opens the on-chain registered commitment before ever proving — refusing to prove with a stale or wrong mandate.

  4. 4

    Portfolio-state-root verification

    Confirms the sequencer-reported portfolio matches the on-chain committed state root. The agent cannot fabricate a healthier portfolio. The sequencer/operator is trusted to post correct state roots after clearing — state-transition proofs are deferred.

  5. 5

    Zero-knowledge compliance proof

    The Noir/UltraHonk circuit cryptographically proves all policy constraints are satisfied simultaneously — whitelist, notional, position, daily loss, and breaker mode.

  6. 6

    On-chain contract verification

    The bb-generated HonkVerifier re-verifies the proof on-chain. The five public inputs (policy commitment, state root, order commitment, epoch, breaker bit) are assembled by the contract from registry state, not taken from calldata.

  7. 7

    Batch-auction epoch commitment

    An order is committed only within the valid commit window of the current epoch; the order commitment binds the epoch, so a proof cannot be replayed against a different one.

  8. 8

    Owner escape hatch

    MandateAccount provides an owner-only withdrawal that depends on nothing — not the agent, sequencer, proof, or auction being alive.

Failure at any single layer is sufficient to prevent an order from being submitted.

Trust assumptions and current limitations

  • This system is experimental and has not undergone an external security audit.
  • It runs entirely on local infrastructure (a local Anvil chain) — there is no public testnet or mainnet deployment.
  • All keys and values are test-only. This is not production custody infrastructure.
  • Session keys and policy salts are secrets and must never be committed to version control.
  • Do not give the same agent unrestricted wallet, swap, transfer, or trading tools alongside mandate_submit_order — proof-gating only works if it is the only execution path.

Developers

Prove and submit an order in a few lines

@0xgks/mandate-sdk — the same MandateClient the MCP server and the demo scripts use internally. Full reference at /docs/sdk.

1. Install

npm install @0xgks/mandate-sdk

2. Import and configure

import { MandateClient } from "@0xgks/mandate-sdk";
import type { MandateClientConfig, PolicyParams, MandateOrder } from "@0xgks/mandate-sdk";

3. Construct the client

mandate-client.ts
// Construct the client's config from environment variables.
// agentId is Poseidon2(session pk, salt) — the agent's on-chain identity.
const policy: PolicyParams = {
  whitelistRoot: BigInt(process.env.MANDATE_WHITELIST_ROOT!),
  maxOrderNotional: BigInt(process.env.MANDATE_MAX_ORDER_NOTIONAL!), // e.g. 1_000_000n
  maxPosition: BigInt(process.env.MANDATE_MAX_POSITION!),
  maxDailyLoss: BigInt(process.env.MANDATE_MAX_DAILY_LOSS!),
  policySalt: BigInt(process.env.MANDATE_POLICY_SALT!),
};

const config: MandateClientConfig = {
  agentId: process.env.MANDATE_AGENT_ID as `0x${string}`,
  sequencerUrl: process.env.MANDATE_SEQUENCER_URL ?? "http://127.0.0.1:8787",
  rpcUrl: process.env.MANDATE_RPC_URL ?? "http://127.0.0.1:8545",
  auctionAddress: process.env.MANDATE_AUCTION_ADDRESS as `0x${string}`,
  registryAddress: process.env.MANDATE_REGISTRY_ADDRESS as `0x${string}`,
  sessionPrivateKey: process.env.MANDATE_SESSION_KEY as `0x${string}`,
  policy,
  circuitDir: process.env.MANDATE_CIRCUIT_PATH ?? "./circuits/policy_check",
};

const mandate = new MandateClient(config);

4. Prove and submit an order

// The order an agent/strategy hands to the SDK — human-friendly,
// string-encoded fields (see MandateOrder in types.ts).
const order: MandateOrder = {
  market: "1",        // circuit market id, as a decimal string
  side: "buy",
  amount: "250",       // whole circuit units, as a decimal string
  limitPrice: "3500",  // whole circuit units, as a decimal string
};

const result = await mandate.proveAndSubmit(order);
// result: { epoch, orderCommitment, proof, publicInputs, txHash }
console.log(`submitted in epoch ${result.epoch}: ${result.txHash}`);

5. Handle a policy rejection

import {
  MandateViolationError,
  PolicyMismatchError,
  PortfolioMismatchError,
  EpochClosedError,
} from "@0xgks/mandate-sdk";

try {
  await mandate.proveAndSubmit({
    market: "1",
    side: "buy",
    amount: "10000",     // 10,000 * 3,500 = 35,000,000 notional
    limitPrice: "3500",
  });
} catch (err) {
  if (err instanceof MandateViolationError) {
    // The order cannot be proven: nargo execute failed on a circuit
    // assertion (e.g. "order notional exceeds mandate maximum").
    // Nothing was submitted on-chain. err.reason is the bare circuit
    // assertion text; err.order is the rejected order.
    console.error(err.reason);
  } else if (err instanceof PolicyMismatchError) {
    // Local plaintext policy doesn't open the on-chain registered
    // commitment — refusing to prove with a stale or wrong mandate.
  } else if (err instanceof PortfolioMismatchError) {
    // Sequencer's reported state root disagrees with the on-chain
    // anchored root — refusing to prove against untrusted state.
  } else if (err instanceof EpochClosedError) {
    // The commit window closed while proving; not submitted.
  }
}

MCP integration

A deliberately narrow tool surface

The MANDATE MCP server exposes exactly three tools. Limiting the tool surface area is itself a security property — an agent cannot do something the server doesn't expose, regardless of what it's instructed to attempt.

Implemented

mandate_get_epoch

Get MANDATE auction epoch state

Implemented

mandate_get_portfolio

Get MANDATE portfolio

MVP

mandate_submit_order

Submit a MANDATE proof-gated order

Comparison

Where MANDATE sits

MANDATE is not intended to replace human approval or wallet-level security. It complements them — the core difference is independent verifiability.

ApproachStrengthLimitation
Prompt instructionsEasy to implement, low overheadModel may ignore, misunderstand, or be manipulated
Human approvalStrong oversight, high trustSlows or prevents autonomous operation
Backend rulesPractical, flexible, widely usedUser must trust the operator; not independently verifiable
Wallet spending limitsUseful financial boundaryCannot express strategy-level or multi-variable rules
MultisigStrong ownership modelNot designed for high-frequency autonomous execution
MANDATEVerifiable, programmable, proof-basedCurrent MVP is local and experimental

Research

The larger protocol vision

MANDATE.pdf describes a long-term protocol: hidden strategies and portfolios, public compliance proofs, pre-committed risk mandates, proof-carrying agent history, and privacy-preserving reputation. None of this is implemented yet — the current MVP demonstrates only the core proof-gated enforcement loop.

MVP

Current working MVP

Real Noir/UltraHonk proofs, on-chain policy commitments, a local batch auction, and a working MCP integration with the MoonPay Agent.

Research

Long-term protocol design

Threshold-encrypted order flow, decentralized keyper committees, Nova-style folded reputation credentials, proved state transitions, and cross-chain settlement via ERC-7683.

Documentation

Two documents, two purposes

Protocol Design Document

MANDATE.pdf

A research-oriented protocol design covering private agent execution, verifiable mandates, cryptographic primitives, market structure, settlement, and privacy-preserving reputation.

Read onlineOpen PDFDownloadSource coming soon

Product Overview

mandate-product-overview.pdf

A practical walkthrough of the working local MVP, SDK, MCP integration, architecture, security model, demo policy, and verified test results.

Read onlineOpen PDFDownloadSource coming soon

Build agents that can act — without giving them unlimited authority.