PCL Built-in Policy Templates

component compliance

The seven policy templates Maroo ships with V1 — denylists, volume limits, attestation gates, KYC-tiered variants, and per-agent transfer caps.

Maroo's PCL ships with seven built-in policy templates that cover the most common regulatory and business compliance gates. Each template defines a Solidity parameter struct (encoded into PolicySet.policy via abi.encode) and an evaluation rule. Administrators instantiate them as PolicySet entries and group them under a GlobalPolicyConfig (network-wide) or ContractPolicyConfig (per-contract). New templates can be registered by governance without touching chain core for use of an existing evaluator; new evaluators require a chain upgrade.

The seven V1 templates

TemplateABI tuplePurpose
DENYLIST_POLICY(address[])Block transactions from listed addresses (sanctions, frozen accounts)
VOLUME_POLICY(string[] tokens, (uint256 minLimit, uint256 maxLimit)[] limits)Per-tx min/max amount per denom (dust prevention, single-tx caps)
PERIODIC_VOLUME_POLICY(string[] tokens, (uint256 maxAmount, uint64 resetPeriodSeconds)[] limits)Cumulative volume limits per reset period (24h, 30d)
EAS_POLICY(address easContract, address indexContract, bytes32 schemaUid)Require valid EAS attestation under a schema (KYC/KYB gate)
OKRW_EAS_TRANSFER_LIMIT_POLICY(address eas, address index, bytes32 schemaUid, uint256 transferLimitAmount)Per-tx OKRW cap that only applies to un-attested senders (tiered access)
OKRW_EAS_PERIODIC_VOLUME_LIMIT_POLICY(address eas, address index, bytes32 schemaUid, uint256 maxAmount, uint64 resetPeriodSeconds)Cumulative OKRW cap that only applies to un-attested senders (Travel-Rule tier)
AGENT_OKRW_TRANSFER_LIMIT_POLICY(uint256 reserved) (no params; cap is read from agent metadata)Per-tx OKRW cap for agent wallets, sourced from on-chain TransferLimit metadata

Follow the sidebar link for each template's page to see the full Solidity struct, abi.encode example, evaluation logic, and ReasonCode behavior.

How they compose

Templates are composable. A typical production GlobalPolicyConfig enforces several at once:

1. DENYLIST_POLICY (sanctioned addresses).
2. OKRW_EAS_TRANSFER_LIMIT_POLICY (un-attested users limited per-tx).
3. OKRW_EAS_PERIODIC_VOLUME_LIMIT_POLICY (un-attested users limited per 24h cumulatively).
4. VOLUME_POLICY (a hard ceiling for everyone, even attested users).

Each PolicySet is evaluated independently; rejection on any one of them rejects the whole transaction with the corresponding ReasonCode. This lets you stack independent compliance gates without designing a monolithic policy. Per-contract configs add a second layer of PolicySets applied only to calls targeting that contract through the regulated path.

Adding new templates

Two distinct paths:

  • New PolicySet using an existing template — only governance work. Build the template-specific struct, abi.encode it, wrap in a PolicySet, submit through the consortium proposal flow. No chain upgrade.
  • New template (new evaluator) — requires a Maroo chain upgrade because the evaluation logic is in x/pcl. Once shipped, governance can register the template and start instantiating PolicySets.


The pattern: when regulators introduce a new requirement that maps to existing template logic, configure it via a new PolicySet. When the requirement needs a fundamentally new evaluation path, ship a new template in the next upgrade.
Source: maroo
ESC
Type to search