PCL 프리컴파일

component compliance

프로그래머블 컴플라이언스 레이어의 EVM 표면으로, 주소는 0x1000…0005입니다. 정책 그래프 조회, 템플릿 및 설정의 등록·변경, PCL 래핑 프록시 배포, 규제 프록시가 매 호출마다 사용하는 preCall/postCall 훅 경로를 제공합니다.

PCL 프리컴파일은 고정된 EVM 주소에 위치한 상태 저장 프리컴파일로, Solidity 코드와 마루의 컴플라이언스 엔진을 연결합니다. 조회 뷰(getParams, globalPolicies, contractPolicies, policyTemplate, 주기 거래량 조회)와 관리자 전용 쓰기(registerPolicyTemplate, setGlobalPolicies, changeContractPolicies 및 각각의 제거 함수)를 제공합니다. 규제 실행 경로도 함께 소유합니다. deployPclProxy는 표준 PCL 래핑 프록시를 배포하며, 이 프록시의 훅 경로가 실제 실행 전후로 preCallpostCall을 호출합니다. 이 훅이 컨트랙트 범위 정책을 발동시키는 유일한 메커니즘입니다.

아키텍처

flowchart LR
    User[EOA / dApp]:::evm --> Proxy[PCL Proxy<br/>Transparent or UUPS]:::evm
    Proxy --> Pre[IPcl.preCall]:::precompile
    Pre --> Logic[Logic Contract]:::evm
    Logic --> Post[IPcl.postCall]:::precompile
    Post --> Result[Return / Revert<br/>with ReasonCode]:::evm

    Admin[Contract Admin]:::evm -.-> ChangeCfg[IPcl.changeContractPolicies]:::precompile
    Reader[Any address]:::evm -.-> Views[IPcl views<br/>contractPolicies / globalPolicies / policyTemplate]:::precompile

    classDef evm fill:#0096AA,stroke:#0096AA,color:#fff;
    classDef precompile fill:#FF8C50,stroke:#FF8C50,color:#fff;

규제 대상 실행은 PCL 프록시를 경유하며, 각 호출을 `preCall`과 `postCall`로 감쌉니다. 컨트랙트 정책 설정은 컨트랙트 admin이 `changeContractPolicies`로 수행하고, 정책 그래프 조회는 누구에게나 열려 있습니다.

주소와 인터페이스

PCL 프리컴파일은 모든 네트워크에서 안정적인 EVM 주소를 가집니다. Solidity 인터페이스는 @maroo-chain/contractsIPcl이며, 같은 패키지의 상수 PCL_PRECOMPILED_ADDRESS가 주소를 고정해 컨트랙트가 하드코딩할 필요를 없앱니다.
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.28;

import {IPcl, PCL_CONTRACT, PCL_PRECOMPILED_ADDRESS} from
    "@maroo-chain/contracts/precompiles/pcl/IPcl.sol";

contract Example {
    IPcl constant pcl = PCL_CONTRACT;                       // 0x1000…0005
    address constant PCL = PCL_PRECOMPILED_ADDRESS;         // 리터럴 형태의 동일 주소
}

메서드 그룹

표면은 네 그룹으로 나뉩니다.

  • 파라미터와 템플릿getParams, policyAdmin, policyTemplate로 조회하고, registerPolicyTemplateremovePolicyTemplate로 템플릿을 등록·해제합니다.
  • 정책 설정globalPoliciescontractPolicies로 현재 설정을 읽고, setGlobalPolicies·removeGlobalPolicies·changeContractPolicies·removeContractPolicies로 바꿉니다.
  • 주기 거래량 조회globalPeriodicVolume, contractPeriodicVolume, globalPeriodicList, contractPeriodicList으로 주기 상한에 대한 현재 사용량을 읽습니다.
  • 규제 실행deployPclProxy로 프록시를 배포하고 pclProxy로 조회하며, PCL에 등록된 프록시가 매 사용자 호출을 감쌀 때 훅 메서드 preCallpostCall을 호출합니다.


PCL 프리컴파일에는 정책 검사와 대상 함수 실행을 한 호출로 처리하는 진입점이 없습니다. 컨트랙트 범위 강제는 모두 프록시의 훅 경로를 통해 흐릅니다.

강제 지점

PCL은 두 지점에서 정책을 평가합니다.

1. 트랜잭션 진입 — 대상과 무관하게 모든 EVM 트랜잭션에 전역 GlobalPolicyConfig가 평가됩니다.
2. 프록시 훅 경로 — 호출이 PCL 등록 프록시를 대상으로 할 때(pcl-proxy-hook 참고), 프록시는 실제 실행 전에 IPcl.preCall(...)을, 실행 후에 IPcl.postCall(...)을 호출합니다. 프록시의 ContractPolicyConfig는 여기서 발동합니다.

프록시를 우회해 컨트랙트 구현체를 직접 호출하는 트랜잭션은 전역 설정만 평가받습니다. 따라서 사용자 대상 진입점으로 프록시 주소를 공개하는 것이 규제 트랙을 실제로 작동시키는 방법입니다.

현재 상태 조회

모든 읽기 뷰는 eth_call을 통한 오프체인 호출 시 가스가 들지 않습니다. 온체인 호출자(자신의 실행 중에 PCL 상태를 읽는 컨트랙트)는 일반 가스를 소모합니다.
import { createPublicClient, http } from "viem";

const PCL = "0x1000000000000000000000000000000000000005" as const;
const pclAbi = [
  { type: "function", name: "policyAdmin", stateMutability: "view",
    inputs: [], outputs: [{ type: "address" }] },
  { type: "function", name: "globalPolicies", stateMutability: "view",
    inputs: [], outputs: [{ type: "tuple", components: [
      { name: "policies", type: "tuple[]", components: [
        { name: "templateId", type: "string" },
        { name: "policy",     type: "bytes"  },
        { name: "selector",   type: "bytes"  },
      ] },
    ] }] },
] as const;

const client = createPublicClient({ transport: http("https://rpc-testnet.maroo.io") });
const admin = await client.readContract({ address: PCL, abi: pclAbi, functionName: "policyAdmin" });
const global = await client.readContract({ address: PCL, abi: pclAbi, functionName: "globalPolicies" });
console.log("정책 관리자:", admin, "활성 전역 정책 수:", global.policies.length);

실패 표면

모든 정책 실패는 IPcl의 타입 지정 커스텀 오류로 나타납니다. 흔한 ReasonCode는 EasNoAttestationReceived, EasAttestationRevoked, EasAttestationExpired, InDenylist, ExceededPeriodicVolume, VolumeAboveMaxLimit, ExceededAgentTransferLimit입니다. 설정 및 관리자 가드 실패는 Unauthorized, PolicyTemplateNotFound, ContractPolicyNotRegistered, PclProxyNotRegistered를 사용합니다. 단일 ContractPolicyConfig 안에서 selector가 중복되면 평문 문자열 duplicate selector: <selector>로 revert됩니다. 타입 지정 오류가 아니므로 문자열로 디코드해야 합니다.
ESC
검색어를 입력하세요