Skip to content
Oris Docs

L5 Revocation

L5 LIVE on Base Sepolia

L5 is the revocation ledger. Every agent and every counterparty can be revoked. The tree proves a party is not revoked at a specific timestamp. Without that proof, the bundle cannot ship.

Two tiers, two cadences. Immediate revocations flush every second so a sanctions hit reaches the network within one Tier 1 batch. Behavioral drift flushes every five minutes since it tolerates slower propagation.

What it does

For every party referenced by a Compliance Bundle (agent, counterparty), L5 returns:

  • the active Merkle root,
  • a non-membership proof showing the party is not revoked,
  • the tree size at the time of proof generation.

A verifier checks the non-membership proof against the recorded root. If the proof verifies, the party was not revoked at bundle time.

Two-tier model

TierTriggerFlushUse case
Tier 1OFAC hit, fraud confirmation, manual blockevery 1 sSanctions, immediate freeze
Tier 2Behavioral drift, KYA demotion, support flagevery 5 minSuspected misuse, soft action

The bundle includes the active tier. A verifier checks the proof against the corresponding root. Tier 1 and Tier 2 use the same SMT structure but separate roots.

Tree shape

  • Sparse Merkle Tree
  • Depth 256 (supports 2^256 leaves, effectively unbounded)
  • Keccak256 hash function (v1, matches L2 for cross-layer Merkle parity)
  • Non-membership proofs O(log n) in size, around 1 KB at current tree size

The migration to Lean IMT and Poseidon-2 is queued behind the L4 ZK boundary in v2.

On-chain commitment

OrisL5RevocationRegistry Base Sepolia

Each tier maintains its own root. Roots commit on chain on flush. The contract enforces monotonic versioning. Replay against a stale root fails because the verifier requires root.version >= bundle.revocation_witness.root.version.

What flows into the bundle

L5 contributes the revocation_witness block:

revocation_witness: {
tier: u8 // 1 or 2
root: bytes32 // tree root at proof time
not_present_proof: bytes // SMT non-membership proof
tree_size: u64
}

The witness is generated in 2 ms or less. The proof is verified against the recorded root in 5 ms or less.

Revocation lifecycle

1. Trigger
- OFAC list update → Tier 1
- Veris drift threshold → Tier 2
- Operator manual block → either tier
2. Revocation entry added to oris_revocation_entries
3. Builder collects entries for the current flush cadence
4. New SMT root computed + signed by Oris MPC ring
5. Root committed to OrisL5RevocationRegistry on Base
6. Next bundle assembly reads the new root

Total time from trigger to active block: under one second for Tier 1, under five minutes for Tier 2.

SDK example

from oris import OrisClient
client = OrisClient(...)
# Revoke an agent (operator action)
client.revocations.create(
subject_did="did:ethr:84532:0x...",
tier=1,
reason="ofac_sdn_hit",
)
# Fetch the current root + non-membership proof
witness = client.revocations.witness(
subject_did=agent.did,
tier=1,
)
print(witness.root)
print(witness.not_present_proof_len)
print(witness.tree_size)

Deploy state

Per-second cadence proven on Base Sepolia. The layer passed its full security audit.

Where to go next