Programmable Compliance Layer (PCL)

compliance external-dapp

An on-chain framework for defining and enforcing custom transaction rules and regulatory policies.

The Programmable Compliance Layer (PCL) is a core module of the Maroo network that enables the creation and enforcement of compliance policies directly on the blockchain. It intercepts transactions before they are processed, validating them against a set of global and contract-specific rules. This allows for the implementation of complex regulatory requirements, such as KYC/AML checks, transfer restrictions, and volume limits, without altering the core logic of smart contracts.

Key Features

Global and Contract-Specific Policies

Apply rules across the entire network or target specific smart contracts for granular control.

Template-Based Policy Creation

Use pre-defined, reusable policy templates (e.g., Denylist, Volume Limits, EAS Attestation) to quickly configure complex rules.

EVM-native integration

Every transaction — EVM call or otherwise — passes through the same PCL gate, so compliance is enforced uniformly at the chain layer.

Extensible via EAS

Uses the Ethereum Attestation Service (EAS) to gate transactions on on-chain attestations — the basis for KYC, KYB, and credential checks.

Architecture

graph TD
    subgraph Transaction Lifecycle
        A[Tx Submitted] --> B{PclAnteDecorator};
        B -- Global Policies --> C{Policy Validator};
        C -- Valid --> D[Execute Tx];
        C -- Invalid --> E[Reject Tx];
        D --> F[State Change];
    end

    subgraph EVM Execution
        G[Contract Call] --> H{EVM Pre-execution Hook};
        H -- Global/Contract Policies --> I(PCL Keeper);
        I --> J{Policy Validator};
        J -- Valid --> K[Execute EVM Logic];
        J -- Invalid --> L[Revert Tx];
    end

    subgraph PCL State
        M[Policy Admin] -- Manages --> N(Policy Templates);
        M -- Manages --> O(Global Policy Config);
        P[Contract Admin] -- Manages --> Q(Contract Policy Config);
        N --> O;
        N --> Q;
    end

The PCL integrates into the transaction lifecycle via an Ante Handler for global checks and into the EVM via pre-execution hooks for both global and contract-specific checks. All policy configurations are stored on-chain and managed by designated admin accounts.

Policy enforcement flow

PCL validates every transaction against a set of rules at the protocol layer.

Every transaction first goes through the AnteHandler — a chain of pre-execution checks. PCL participates in that chain by loading all active Global Policies and running them against the transaction (sender, recipient, value, etc.). If any global policy fails, the transaction is rejected before it consumes significant gas.

For EVM transactions there's an additional layer. The chain calls into PCL again before executing the EVM call, and at that stage PCL also runs the Contract-specific Policies registered against the target contract address. The two layers together — global at AnteHandler, contract-scoped at EVM call — give consistent enforcement across the entire network.
Note: The AnteHandler check rejects invalid transactions before they reach the mempool, saving network resources and giving the user immediate feedback.

Policy Templates and Configuration

Instead of defining rules from scratch, PCL uses a template-based system. A PolicyTemplate is a blueprint for a type of rule — its canonical Solidity struct in IPcl.sol declares the parameter layout for instances. Maroo comes with seven built-in templates (DENYLIST_POLICY, VOLUME_POLICY, PERIODIC_VOLUME_POLICY, EAS_POLICY, OKRW_EAS_TRANSFER_LIMIT_POLICY, OKRW_EAS_PERIODIC_VOLUME_LIMIT_POLICY, AGENT_OKRW_TRANSFER_LIMIT_POLICY).

The PolicyAdmin, a privileged account set in the module's parameters (controllable by governance), is responsible for registering and managing these templates.

To activate a rule, an administrator creates a PolicySet — a { templateId, policy, selector } tuple where policy is the ABI-encoded parameter struct for that template (NOT JSON). For example, a denylist is a PolicySet with templateId = "DENYLIST_POLICY", policy = abi.encode(DenylistPolicy({ addresses: [...] })), and selector = bytes4(0) (apply to all calls). PolicySet objects are then grouped into a GlobalPolicyConfig (chain-wide) or ContractPolicyConfig (per-contract) to be applied.

Next Steps

Source: maroo
ESC
Type to search