Home
Mandant
MANDANT/ DOCS
THE FINANCIAL CONTROL LAYER FOR AI SWARMS

Mandant Developer Hub & Architecture Specification

Mandant is an EVM-native financial control layer that allows orchestrators and institutional treasuries to give autonomous software access to capital without granting unrestricted wallet authority.

When AI agents operate with flat private keys (MetaMask, EOA, or unconstrained smart accounts), a single prompt injection, context hallucination, or runaway loop can drain the entire wallet balance in one block. Mandant replaces flat accounts with a recursive hierarchy of bounded mandates, outcome-verified escrow (ERC-8183), and 1-transaction subtree circuit breakers.

The Three Core Protocol Primitives

1. Hierarchical Budget Attenuation

A treasury creates a Root Mandate in MandateHub.sol. Parent agents delegate micro-budgets downward to child agents. Authority moves strictly downward: children cannot exceed their parent budget ceiling or expand beyond their parent's allowlisted tools (monotonic attenuation).

2. Outcome-Verified Escrow (ERC-8183)

Agents do not pay external service providers upfront. Payments are locked into JobAdapter.sol against an expected deliverable hash. An evaluator contract (HashMatchEvaluator.sol) deterministically checks the deliverable before funds release. If the output is corrupted or timed out, 100% of the funds are refunded.

3. 1-Transaction Subtree Circuit Breakers

When a worker agent behaves suspiciously, an operator or authorized watchdog sentinel executes revokeSubtree() in a single transaction. The rogue branch is quarantined, unspent capital sweeps upward, and independent sibling workflows continue without downtime.

Quickstart Installation

Mandant adheres strictly to modern package managers. Install the SDK via bun or pnpm:

$ bun add @mandant/sdk viem
AI Framework Adapter

LangChain Integration (TypeScript & Python)

Wrap any tool invocation in an outcome-conditioned Mandant escrow. If an LLM hallucinations generate invalid schema outputs, the smart contract prevents capital release.

mandant-langchain-tool.ts
import { DynamicStructuredTool } from "@langchain/core/tools"
import { z } from "zod"
import { MandantClient } from "@mandant/sdk"
import { keccak256, toHex } from "viem"

export function createMandantEscrowTool(client: MandantClient, workerMandateId: `0x${string}`) {
  return new DynamicStructuredTool({
    name: "mandant_outcome_escrow",
    description: "Funds an ERC-8183 escrow for paid computation with onchain hash verification",
    schema: z.object({
      providerAddress: z.string().describe("Recipient service provider address"),
      amountUsdc: z.number().describe("Budget in USDC (e.g. 250)"),
      expectedDeliverableText: z.string().describe("Expected JSON schema or hash contract"),
    }),
    func: async ({ providerAddress, amountUsdc, expectedDeliverableText }) => {
      const expectedHash = keccak256(toHex(expectedDeliverableText))
      const amountUnits = BigInt(amountUsdc * 1e6)

      // 1. Lock funds into onchain JobAdapter
      const lockTx = await client.fundJob({
        mandateId: workerMandateId,
        provider: providerAddress as `0x${string}`,
        amount: amountUnits,
        deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
        expectedDeliverableHash: expectedHash,
      })

      return `Escrow locked in tx ${lockTx}. Funds protected by MandateTree balance conservation.`
    },
  })
}

CrewAI Multi-Agent Swarm Adapter (Python)

When using CrewAI, individual autonomous workers can be given bounded budget ceilings. Sub-agents use this tool to hire peer agents without ever holding root vault private keys:

crewai_mandant_tool.py
from crewai.tools import BaseTool
from web3 import Web3

class CrewAIMandantTool(BaseTool):
    name: str = "delegate_budget_to_peer"
    description: str = "Delegates an attenuated micro-budget to a sub-worker agent in the swarm"

    def _run(self, peer_agent_address: str, budget_usdc: float) -> str:
        # Spawns depth-2 child mandate via MandateTree.spawn()
        print(f"Spawning child mandate for {peer_agent_address} with {budget_usdc} USDC limit")
        return f"Child mandate active on BNB Testnet. Invariant preserved: Idle - {budget_usdc} USDC."

ElizaOS Agent Plugin (TypeScript)

Native ElizaOS plugin providing the MANDANT_ESCROW_PAY action and evaluator:

eliza-mandant-plugin.ts
import { type Plugin, type Action, type IAgentRuntime, type Memory } from "@elizaos/core"

export const mandantEscrowPlugin: Plugin = {
  name: "mandant-escrow",
  description: "Enforces hierarchical budget constraints and outcome-verified settlement on ElizaOS agents",
  actions: [
    {
      name: "MANDANT_ESCROW_PAY",
      similes: ["PAY_VENDOR_WITH_ESCROW", "LOCK_BUDGET_FOR_TASK"],
      validate: async (runtime: IAgentRuntime, message: Memory) => true,
      handler: async (runtime, message, state, options, callback) => {
        callback?.({
          text: "Locked $250 USDC in ERC-8183 escrow. Release conditioned upon hash verification.",
        })
        return true
      },
    },
  ],
}
Mathematical Foundation

Formal Verification: Balance Conservation Law

At every block, Mandant guarantees that capital in the vault matches the exact sum of all downward delegations and open escrow locks.

Fundamental Invariant Equation
Idle + ∑ ChildGranted + LockedInJobs = GrantedBudget
• Idle: Unallocated, liquid USDC available for jobs or child delegation.
• ChildGranted: Sum of all budgets delegated downward to immediate children.
• LockedInJobs: Collateral currently held in JobAdapter escrow awaiting delivery.
• GrantedBudget: Hard ceiling deposited by the parent or root treasury.

Deep Dive: The Lazy Ancestor Walk in _sync()

In deep hierarchical swarms (e.g. Depth 1 Orchestrator $\to$ Depth 2 Worker $\to$ Depth 3 Sub-Agent), traversing the entire tree to revoke every grandchild eagerly would exceed EVM gas limits. Mandant implements an O(1) lazy downward synchronization algorithm:

MandateTree.sol (_sync implementation)Verified Bytecode
function _sync(bytes32 mandateId) internal {
    MandateNode storage node = nodes[mandateId];
    if (node.status == NodeStatus.REVOKED) return;

    // 1. Check self expiry
    if (block.timestamp >= node.expiry && node.status == NodeStatus.ACTIVE) {
        node.status = NodeStatus.EXPIRED;
        _sweepIdleUp(mandateId);
        return;
    }

    if (node.parentId == bytes32(0)) return;

    // 2. Multi-hop ancestor walk up to MAX_DEPTH (5 hops)
    bytes32 curr = node.parentId;
    bool shouldRevoke = false;
    for (uint8 d = 0; d < MAX_DEPTH && curr != bytes32(0); d++) {
        MandateNode storage anc = nodes[curr];
        if (anc.status == NodeStatus.REVOKED || anc.status == NodeStatus.EXPIRED || block.timestamp >= anc.expiry) {
            shouldRevoke = true;
            break;
        }
        curr = anc.parentId;
    }

    // 3. Lazy revocation cascade and capital sweep
    if (shouldRevoke) {
        node.status = NodeStatus.REVOKED;
        _sweepIdleUp(mandateId);
    }
}
Why this architecture wins:
1. Single-Transaction Execution: Revoking an orchestrator takes 1 transaction. It does not loop over 50 child nodes.
2. Immediate Quarantine: The moment any child attempts an action, _sync() checks its ancestors, revokes the child, and sweeps its idle funds upward before any state can change.

Capital Recovery: _sweepIdleUp()

When a child is revoked, its idle balance is swept upward to the nearest active ancestor, restoring invariant balance conservation:

function _sweepIdleUp(bytes32 mandateId) internal returns (uint128 swept) {
    MandateNode storage node = nodes[mandateId];
    swept = node.idle;
    node.idle = 0;

    if (node.parentId == bytes32(0) || swept == 0) return swept;

    bytes32 curr = node.parentId;
    while (curr != bytes32(0)) {
        MandateNode storage ancestor = nodes[curr];
        if (ancestor.status == NodeStatus.ACTIVE) {
            ancestor.idle += swept;
            if (ancestor.childGranted >= swept) {
                ancestor.childGranted -= swept;
            } else {
                ancestor.childGranted = 0;
            }
            break;
        }
        curr = ancestor.parentId;
    }
}

Interactive Balance Conservation Sandbox

Adjust the sliders below to simulate how an agent allocates its $10,000 USDC budget across idle capital, child delegations, and escrow locks:

Live Mathematical Verification✓ 100% CONSERVED
Idle Liquid Balance$6,000 USDC
Sub-Allocations to Children$3,000 USDC
Locked in ERC-8183 Jobs$1,000 USDC
Current Sum: $10,000 USDC
Target Ceiling: $10,000 USDC

Center Guard & Policy Commitments

Launch Full Studio

Every mandate commits an onchain policy hash: policyHash = keccak256(policyJson). The EVM checks that:

Allowlist(Child) ⊆ Allowlist(Parent) ∧ SpendPerJob ≤ MaxJobCeiling

ERC-8004 Agent Identity & Attributed DIDs

When an agent is quarantined, revoking its mandate sweeps its capital but preserves its ERC-8004 DID (did:8004:bsc:worker-beta) onchain in MandateLog.sol. This ensures malicious LLMs cannot respawn clean identities.

Agent Risk Scoring & Credit Engine (agentRiskScore)

LPs and protocols can query the onchain credit score of any worker before delegating liquidity:

Score = 100 - (30 * InvariantDisparities) - (20 * Revocations) + (20 * SettleRatio)
AAA rating: 95-100 · AA rating: 90-94 · High Risk: < 70

Verified BNB Smart Chain Testnet Contracts

Chain ID: 97

All 6 core contracts are verified on BscScan. Click any card to inspect the live bytecode or copy the contract address:

0x0b3a2d73d07ea2d5d0d0fb4db09004f74d92767a
USDC Collateral Vault, Protocol Fees (50 bps), Root Entrypoint
0x9f1888516d1c087f835f594892b915dd9dcbe5f1
Recursive DAG Hierarchy, Downward Attenuation, 1-Tx Revocation
0xa6a6dcad668470d3bfc5c73938b4558e5aad1505
ERC-8183 Outcome-Verified Escrow & SLA Enforcement
HashMatchEvaluatorBscScan Verified ↗
0x7c6aa54eaeea04cf8950b1451faf0b21cb6037c2
Deterministic keccak256 Deliverable Verification
0xf086ab5734ee1cd10235f6f5f7f7fc542d78e98e
Incremental Event Log & Epoch Merkle Commitments
0x419cfe85e77a0a26b9989059057318f59764f7c5
Circle 6-decimal standard ERC-20 payment asset

MandantClient Core Methods Reference

client.createRoot(params)
Deposits collateral into MandateHub and initializes root DAG tree.
client.spawn(params)
Spawns an attenuated child mandate under parentId with strict subset allowlist.
client.fundJob(params)
Locks funds into ERC-8183 escrow for provider against expectedDeliverableHash.
client.revokeSubtree(mandateId)
Executes atomic 1-Tx cascade kill switch and sweeps unspent capital home.