Skip to main content

Rate Limits

Any err increments violations. Any ok clears all violations instantly. Per-principal, per-canister.

TierViolationsEffectRecovery
00-9Normal--
110-19SOFT_BLOCKED, 5 min cooldownWait cooldown, succeed once to reset
220+Silent reject at inspectWait 24h or release_rate_limit()

Soft Block

Returns SOFT_BLOCKED with metadata:

  • blocked_until_ms — sleep until this timestamp
  • tries_left — violations remaining before hard block

One success after cooldown clears all violations (back to Tier 0). One failure adds another 5 min cooldown.

Hard Block

Rejected at inspect_message — no error body, call silently fails. If all calls fail with no response, you are hard-blocked.

Recovery:

  1. Wait 24h (hourly cleanup removes inactive blocks)
  2. release_rate_limit(blocked_principal) from a second identity — see below

release_rate_limit()

A hard-blocked principal cannot call the canister. A second identity pays to release it.

// caller = unblocked principal with ICRC-2 allowance on quote token
release_rate_limit(blocked_principal)
// cost: 10x quote token ledger fee + 1x operation fee = 11x total
// pulled from caller's wallet via ICRC-2 transfer_from (NOT trading balance)

The caller must have an ICRC-2 allowance set on the quote token ledger for the spot canister. On success, blocked principal returns to Tier 0 immediately. Maintain a funded secondary identity with a standing allowance as a recovery path.

What Counts

Tracked (increments violations): any command returning err — validation, state, external errors.

Not tracked: query calls, successful commands, calls rejected at inspect.

The rate limiter penalizes repeated errors, not request volume.