EIP.tools

EIP.tools

⚠️ ReviewStandards Track: ERC

ERC-7972: Universal Compliance Router for RWA's

UniversalComplianceRouter is an on-chain router that coordinates modular, pluggable compliance checks for tokenized RWAs

Authors
Created2025-06-16
Discussion Linkhttps://ethereum-magicians.org/t/erc-7972-universal-compliance-router-for-rwas-security-tokens/24564

Markdown

https://raw.githubusercontent.com/ethereum/ERCs/re...
Pull Request#1087PR open

EIP-GPT summary

Contents
AbstractMotivationSpecificationRationaleHigh level ArchitectureBackwards CompatibilitySecurity ConsiderationsCopyright

Abstract

This EIP introduces a UniversalComplianceRouter contract that acts as a universal compliance layer for RWA security tokens. It allows dynamic registration of compliance modules, each associated with a function selector. The router performs aggregated compliance checks by invoking these modules with user-specific parameters such as jurisdiction using staticcall method. This enables flexible, composable, and upgradable compliance enforcement across jurisdictions and asset classes.

Motivation

On-chain compliance for tokenized real-world assets (RWAs) such as money market funds, real estate, private equity, and fixed-income securities etc. is becoming essential as adoption increases. Regulatory frameworks (KYC, AML, accredited investor rules, jurisdiction-specific rules) are often complex, evolving, and differ across asset classes and countries.

Currently, developers hardcode compliance logic into token contracts or wrap tokens with enforcement proxies. These approaches are:

  • Inflexible: They require contract redeployments to update rules.
  • Siloed: Each protocol creates and audits its own compliance logic.
  • Non-composable: Tokens, marketplaces, and identity services cannot easily interoperate.

This results in duplicated effort, increased audit surface, and fragmentation across ecosystems.

We need a shared, modular, and extensible compliance layer that:

  • Allows for dynamic updates to compliance rules
  • Enables jurisdiction-specific enforcement logic
  • Promotes reuse and composability across protocols
  • Encourages collaboration between identity providers, compliance services, and token issuers

The UniversalComplianceRouter addresses these needs by serving as a pluggable registry and execution layer for compliance modules that can be applied across different asset types, jurisdictions, and lifecycle events.

Specification

Note: The interface and implementation below can be extended to include KYC levels and other KYC/AML checks as parameters in the isCompliant function. The core idea is to allow the registration of compliance frameworks or sub-proxies within the Universal Compliance Router, each exposing a unified callable selector for a specific category of compliance contracts. The registered sub-router/proxy or compliance contract counts in the Universal Compliance Router should be optimized to reduce the computational cost associated with looping operations.

Interface

// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;

/// @title IUniversalComplianceRouter
/// @notice Interface for a modular compliance router supporting general and jurisdiction-aware compliance contracts
interface IUniversalComplianceRouter {
    /// @notice Emitted when a general compliance contract is registered
    /// @param contractAddress The address of the registered contract
    /// @param selector The function selector used for compliance checks
    event GeneralComplianceContractRegistered(address indexed contractAddress, bytes4 selector);

    /// @notice Emitted when a jurisdiction-aware compliance contract is registered
    /// @param contractAddress The address of the registered contract
    /// @param selector The function selector used for compliance checks
    event JurisdictionAwareComplianceContractRegistered(address indexed contractAddress, bytes4 selector);

    /// @notice Emitted when a general compliance contract is removed
    /// @param contractAddress The address of the removed contract
    event GeneralComplianceContractRemoved(address indexed contractAddress);

    /// @notice Emitted when a jurisdiction aware compliance contract is removed
    /// @param contractAddress The address of the removed contract
    event JurisdictionAwareComplianceContractRemoved(address indexed contractAddress);

    /// @notice Registers a general compliance contract
    /// @param contractAddress The address of the compliance contract
    /// @param selector The function selector (e.g., isCompliant(address))
    function registerGeneralComplianceContract(address contractAddress, bytes4 selector) external;

    /// @notice Registers a jurisdiction-aware compliance contract
    /// @param contractAddress The address of the compliance contract
    /// @param selector The function selector (e.g., isCompliant(address, bytes32))
    function registerJurisdictionComplianceContract(address contractAddress, bytes4 selector) external;

    /// @notice Removes a compliance contract from the registry
    /// @param contractAddress The address of the contract to remove
    function removeComplianceContract(address contractAddress) external;

    /// @notice Checks if a user is compliant with any general compliance contract
    /// @param user The address of the user to check
    /// @return True if compliant with any general contract, false otherwise
    function isCompliant(address user) external view returns (bool);

    /// @notice Checks if a user is compliant with any jurisdiction-aware compliance contract
    /// @param user The address of the user
    /// @param jurisdiction The jurisdiction identifier (e.g., country code)
    /// @return True if compliant with any jurisdiction-aware contract, false otherwise
    function isCompliant(address user, bytes32 jurisdiction) external view returns (bool);

    /// @notice Returns the number of general compliance contracts
    /// @return The number of general compliance contracts registered
    function getGeneralComplianceContractCount() external view returns (uint);

    /// @notice Returns the number of jurisdiction-aware compliance contracts
    /// @return The number of jurisdiction-aware compliance contracts registered
    function getJurisdictionAwareContractCount() external view returns (uint);

}

Rationale

The UniversalComplianceRouter is designed with the following decisions:

  • Modular Contract Registration: Compliance contracts are registered with their corresponding function selectors (bytes4) to allow for diverse validation logic without assuming fixed interfaces. This allows backwards-compatible upgrades and supports heterogeneous compliance frameworks.

  • Staticcall for Safety: Compliance checks are invoked via staticcall, ensuring they are read-only and cannot modify state. This makes the router safe to integrate with other on-chain systems and supports off-chain simulation for auditability.

  • Dual Registry Design: The router maintains separate lists for:

    • General compliance contracts: which apply globally,
    • Jurisdiction-aware contracts: which are checked conditionally based on the user’s jurisdiction (passed as a bytes32 identifier).

    This split improves clarity and allows different enforcement strategies to coexist.

  • Iterative Check Model: The router returns true on the first passing check. This conservative model optimizes for gas efficiency while enabling compliance layering.

  • Owner-controlled Registration: To avoid misuse, only the deployer (or designated admin) can register or remove compliance modules. This can later be extended to role-based or DAO-based control models.

This architecture provides a low-coupling, high-composability mechanism for evolving compliance logic that can serve as shared infrastructure for the RWA ecosystem.

High level Architecture

Universal Compliance Router

Backwards Compatibility

There are no backwards compatibility concerns.

Security Considerations

TODO

Copyright and related rights waived via CC0.

EIP.tools

EIP.tools

Search, read, and map Ethereum improvement proposals, ERCs, RIPs, and CAIPs from one focused interface.

Farcaster
by @apoorveth