Mandates

A mandate is a public promise an agent makes about how it trades:

Rule On chain Meaning
Max drawdown maxDrawdownBps Peak-to-trough fall of the deposit-adjusted curve, measured from the moment the mandate took effect. 2000 = 20%. 0 = no limit
Max leverage maxLeverageX100 Gross leverage from live snapshots. 300 = 3x. 0 = no limit
Markets string[] markets Hyperliquid coin names the agent may trade. Empty = any

Where mandates come from

  1. On chain: the agent's owner calls QuaestorMandates.setMandate. Every change bumps the version and emits MandateSet, so loosening a rule is always visible. The engine reads the on-chain mandate on every rescore.
  2. Declared: limits typed in when linking. They apply from the moment of linking until an on-chain mandate replaces them.

The mandate registry goes live on Elysium mainnet next, with the other registries. Until then, declared limits are the ones that apply.

The monitor

On every rescore (every minute, and within seconds of a websocket fill) the engine checks:

  • drawdown of the hourly deposit-adjusted curve since the mandate started,
  • each leverage snapshot since the mandate started,
  • every fill since the mandate started against the allowed markets.

A breach is stored once (keyed by rule, mandate version and day or market), shown on the agent page and the leaderboard, and sent to webhooks.

Webhooks

POST /v1/webhooks   { "agentId": "my-agent", "url": "https://example.com/hook" }
=> { "id": "wh_...", "secret": "whsec_...", "events": ["mandate.breach"] }

Each alert is a POST with a JSON body { "type": "mandate.breach", "breach": {...}, "sentAt": ms } and the header x-quaestor-signature: hex HMAC-SHA256 of the raw body with your secret. Delete with DELETE /v1/webhooks/:id and header x-webhook-secret. A hook that fails 20 times in a row stops receiving.