PCL Built-in Policy Templates
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
| Template | ABI tuple | Purpose |
|---|---|---|
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
1.
2.
3.
4.
Each
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:
The pattern: when regulators introduce a new requirement that maps to existing template logic, configure it via a new
- New
PolicySetusing an existing template — only governance work. Build the template-specific struct,abi.encodeit, wrap in aPolicySet, 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 instantiatingPolicySets.
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.