PCL ReasonCode

mechanism compliance

PCL이 트랜잭션을 거절할 때 발행하는 커스텀 오류 전체와 이제 상속받는 IPrecompile 공유 오류를 함께 다룹니다. 지갑과 SDK는 이 코드들을 기준으로 사용자 경험을 구성합니다.

PCL의 모든 거절은 IPcl에 선언된 커스텀 Solidity 오류 중 하나를 전달합니다. IPcl이 이제 IPrecompile을 상속하므로 공유 경계 오류도 포함됩니다. 지갑과 dApp 코드는 revert 페이로드를 IPcl ABI(전이적으로 IPrecompile 오류를 포함)로 디코드하고, 자유 형식 문자열이 아니라 오류 이름과 인자를 기준으로 사용자 경험을 구성합니다. 코드는 네 그룹으로 나뉩니다. 정책 위반 코드(사용자 트랜잭션이 컴플라이언스 규칙에 실패), 설정 코드(관리자 호출이 잘못되었거나 권한이 없음), 조합/구조 코드(LogicalPolicy 또는 ForEachPolicy 조합기가 거절), 그리고 상속된 경계 오류(잘못된 주소, 인자 개수 불일치, 알 수 없는 메서드, SDK 수준 거절)입니다. 일부 실패는 여전히 평문 문자열 revert이며 커스텀 오류로 디코드할 수 없습니다. 해당 항목은 명시적으로 표시합니다.

정책 위반 ReasonCode

사용자 트랜잭션이 리프 정책에 도달했고 그 정책이 거절할 때 발생합니다. 지갑 UX가 가장 관심 있는 코드들이며, 최종 사용자에게 결제가 차단된 이유를 알려줍니다.

오류인자의미
InDenylistaddress sender발신자(또는 해석된 주체)가 denylist에 있습니다.
VolumeBelowMinLimituint256 minLimit, uint256 value전송 금액이 트랜잭션당 하한 미만입니다.
VolumeAboveMaxLimituint256 maxLimit, uint256 value전송 금액이 트랜잭션당 상한을 초과합니다.
ExceededPeriodicVolumeuint256 maxLimit, uint256 value, uint256 resetAt롤링 윈도 상한을 초과합니다. resetAt은 현재 윈도가 재설정되는 시각입니다.
EasAttestationRequiredaddress sender정책이 요구하는 attestation을 발신자가 보유하지 않습니다.
EasNoAttestationReceivedaddress sender지정된 스키마로 발신자에 대해 인덱서가 attestation을 반환하지 않았습니다.
EasAttestationLookupFailedaddress sender인덱서 조회 자체가 실패했습니다.
EasAttestationRevokedaddress senderattestation이 존재하지만 취소되었습니다.
EasAttestationExpiredaddress senderattestation이 존재하지만 expirationTime을 지났습니다.
ExceededAgentTransferLimituint256 maxLimit, uint256 value에이전트의 온체인 TransferLimit 메타데이터 상한을 초과했습니다.
AgentTransferLimitMetadataInvalidstring reason에이전트 메타데이터가 잘못되었습니다.
AgentKeeperRequired에이전트 정책을 평가했으나 에이전트 모듈이 연결되어 있지 않습니다.

설정 ReasonCode

관리자 작업(registerPolicyTemplate, changeContractPolicies, setGlobalPolicies 등)에서 페이로드가 잘못되었거나 호출자가 권한이 없을 때 발생합니다.

오류인자의미
CannotEmptystring field필수 필드가 비어 있습니다.
Unauthorized호출자가 요구되는 admin(정책 admin, 컨트랙트 admin, 보호된 호출자)이 아닙니다.
InternalError모듈 내부에서 state 인코딩/디코딩이 실패했습니다.
InvalidCall호출 컨텍스트 자체가 잘못되었습니다(예: EVM 없이 deployPclProxy 호출).
InvalidStructTypestring gotABI struct가 잘못된 형태로 디코드되었습니다.
AbiDecodeFailedstring reason원시 ABI 디코드가 실패했습니다(initData 형식 오류 등).
InvalidParameterbytes input파라미터 바이트가 템플릿의 예상 struct와 일치하지 않습니다. 중복 selector에도 발생하며, 페이로드는 원시 selector 바이트입니다.
InvalidSelectorbytes inputselector가 4바이트 값이 아닙니다.
InvalidPolicyTemplatestring input템플릿 ID 문자열이 인식되는 템플릿이 아닙니다.
DuplicatedPolicyTemplatestring templateId이미 존재하는 템플릿을 등록하려고 했습니다.
PolicyTemplateNotFoundstring templateId템플릿 ID가 등록되어 있지 않습니다.
PolicyTemplateInUse활성 PolicySet이 참조하는 템플릿을 제거하려고 했습니다.
UnknownPolicyTypestring templateId이 빌드가 평가할 수 있는 템플릿 ID가 아닙니다.
UnknownPolicyConfigType상위 config 타입이 Global도 Contract도 아닙니다.
PolicyAlreadyRegisteredaddress contractAddress생성 경로에서 이 주소의 ContractPolicyConfig가 이미 존재합니다.
ContractPolicyNotRegisteredaddress contractAddress갱신/제거 경로에서 이 주소의 ContractPolicyConfig가 없습니다.
PclProxyNotRegisteredaddress contractAddress이 주소는 등록된 PCL 래핑 프록시가 아닙니다.
PolicyNotRegisteredstring templateIdPolicySet이 참조하는 템플릿이 등록되어 있지 않습니다.

조합 및 구조 ReasonCode

LogicalPolicyForEachPolicy 조합기(pcl-composite-policies 참고)는 조합기가 어떻게 거절했는지 설명하는 구조적 오류로 실패할 수 있습니다. 특히 중요한 것은 AnyOfRejected이며, 자식 revert들을 재귀적으로 감쌉니다.

오류인자의미
AnyOfRejectedbytes[] childRevertsOr 조합기의 자식들이 모두 거절되었습니다. 각 자식 revert가 원시 ABI 바이트로 보존되어 클라이언트가 개별적으로 디코드할 수 있습니다.
MaxDepthExceededuint8 maxDepth조합기 중첩이 구조적 깊이 제한을 초과했습니다.
ChildSelectorNotEmpty조합기의 자식 PolicySet은 빈 selector여야 하는데 비어 있지 않은 값이 제공되었습니다.
LogicalPolicyChildrenEmptyLogicalPolicy.children 배열이 비어 있습니다.
LogicalPolicyChildNiluint256 index주어진 인덱스의 자식이 nil PolicySet으로 디코드되었습니다.
ForEachChildAbsentForEachPolicy.child가 설정되지 않았습니다.
ForEachSubjectUnspecifiedForEachPolicy.subjectUnspecified입니다.
UnknownForEachSubjectuint8 subjectsubject 값이 알려진 ForEachSubject가 아닙니다.
QuantifierUnspecified조합기의 quantifier가 Unspecified입니다.

AnyOfRejected를 디코드할 때는 childReverts 배열을 순회하며 각 항목을 다시 IPcl ABI로 디코드해 기반이 되는 리프 오류를 노출합니다.

상속된 IPrecompile 오류

IPcl이 이제 IPrecompile을 상속하므로, 모든 공유 경계 오류를 동일한 ABI로 디코드할 수 있습니다. 이 오류들은 정책 코드가 실행되기 전에 발생하며, 프리컴파일 경계의 잘못된 입력이나 SDK 수준 거절을 나타냅니다.

오류인자발생 시점
InvalidAddressstring badaddress 인자가 0 주소이거나 인코딩에 실패합니다. 페이로드가 이전에 로컬로 선언되었던 string input이 아니라 string(16진수로 표현된 주소)이라는 점에 주의합니다. selector는 IPrecompile 쪽 값을 사용합니다.
InvalidAmountstring amount수치 금액이 0이거나 유효하지 않습니다.
InvalidNumberOfArgsuint256 expected, uint256 got프리컴파일이 잘못된 ABI 인자 개수를 받았습니다. 대개는 오래된 ABI가 원인입니다.
UnknownMethodstring methodNameselector가 프리컴파일의 어떤 함수와도 일치하지 않습니다.
InvalidPageRequeststring method, uint256 index, string value(주기 목록 뷰의) PageRequest 인자가 잘못되었습니다.
SDKUnauthorized / SDKInvalidAddress / SDKInvalidRequest / SDKNotFound / …매핑된 SDK 오류 카탈로그를 통해 노출되는 하부 체인 계층 거절입니다.

이전에 IPcl의 로컬 InvalidAddress(string input) 형태만 매칭하던 클라이언트는 ABI 조각을 IPrecompile의 InvalidAddress(string bad)로 갱신해야 합니다. 인자 이름이 바뀌고 선언 인터페이스가 이동했지만, InvalidAddress(string)의 4바이트 selector는 변하지 않았습니다.
import { decodeErrorResult } from "viem";
import IPclAbi from "@maroo-chain/contracts/abi/IPcl.json";

try {
  await wallet.writeContract({ /* ... PCL 호출 ... */ });
} catch (err: any) {
  if (!err?.data) throw err;
  const decoded = decodeErrorResult({ abi: IPclAbi, data: err.data });
  // decoded.errorName은 IPcl reason code 중 하나이거나
  // 상속된 IPrecompile 오류(InvalidAddress, InvalidNumberOfArgs, UnknownMethod, ...)입니다.
  switch (decoded.errorName) {
    case "InDenylist":
    case "ExceededPeriodicVolume":
    case "EasAttestationRevoked":
      // 정책 위반 UX
      break;
    case "Unauthorized":
    case "PolicyTemplateNotFound":
      // admin / 설정 UX
      break;
    case "AnyOfRejected":
      // decoded.args[0]: bytes[]를 재귀적으로 디코드
      break;
    case "InvalidAddress":
    case "InvalidNumberOfArgs":
    case "UnknownMethod":
      // 경계 오류입니다. 대개 오래된 ABI 또는 잘못된 인자 타입이 원인입니다.
      break;
    default:
      console.warn("처리되지 않은 PCL revert:", decoded.errorName, decoded.args);
  }
}

커스텀 오류가 아닌 실패

일부 PCL 실패는 여전히 평문 문자열 revert이며 decodeErrorResult로 디코드할 수 없습니다. 문자열 revert로 매칭합니다.

  • duplicate selector: <selector> — 같은 설정 안의 두 PolicySet 항목이 selector를 공유합니다. (현재는 ABI 계층에서 InvalidParameter selector를 통해 보고되기도 하지만, 과거 클라이언트는 여전히 문자열 형태로 노출될 수 있으니 두 경로 모두 디코드합니다.)
  • pcl keeper is not initialized — 이 빌드에 모듈이 연결되어 있지 않습니다. 사용자 오류가 아니라 노드 설정 오류입니다.
  • pcl: parse IPcl.json: <err> — 모듈 초기화 실패입니다. 실제 dApp에는 노출되지 않습니다.


이 페이지에 나열된 그 외 모든 실패는 커스텀 오류이며 IPcl ABI로 디코드해야 합니다.
ESC
검색어를 입력하세요