IPcl.preCall

preCall(address contractAddress, address principal, bytes calldata data, uint256 value) external returns (bytes32 sessionId)

프록시 호출을 위한 PCL 정책 평가 세션을 엽니다. PCL로 래핑된 프록시 훅이 구현체를 delegatecall하기 전에 호출합니다. preCallcontractAddress에 등록된 ContractPolicyConfig(존재하는 경우)와 체인 전역 GlobalPolicyConfig를 전달된 principal / data / value에 대해 평가하고, 주기 거래량 등 누적형 정책에 필요한 사전 상태를 스냅숏한 뒤, 짝이 되는 postCall이 제시해야 할 sessionId를 반환합니다. 정책 중 하나라도 거절하면 해당 PCL ReasonCode로 revert됩니다.

파라미터

이름 타입 필수 설명
contractAddress address PCL 정책 조회 키로 사용되는 프록시 주소입니다. 등록된 ContractPolicyConfig 항목이 이 주소로 매칭됩니다.
principal address 프록시가 관찰한 호출의 실제 발신자(EOA 또는 AA 스마트 계정)입니다. PCL이 보는 직접 호출자(msg.sender)는 프록시이므로, 이 인자를 명시적으로 전달하지 않으면 sender / principal denylist 검사가 발동하지 않습니다.
data bytes 구현체로 전달되는 원본 내부 calldata입니다. 앞 4바이트(존재하는 경우)를 함수 selector로 추출하여 selector 범위 PolicySet과 매칭합니다.
value uint256 호출에 첨부된 네이티브 값(aokrw 단위)입니다. 거래량 기반 정책의 입력으로 사용됩니다.

반환값

타입: bytes32

delegatecall이 끝난 뒤 postCall로 다시 전달해야 하는 세션 식별자입니다. 세션은 post-call 시점의 누적형 정책 평가에 필요한 사전 로그 오프셋과 네이티브 전송 수집기를 보관합니다.

에러

코드 이름 설명
Unauthorized Unauthorized 직접 호출자가 허용된 PCL 프록시 진입점이 아니면 revert됩니다(PCL에 등록된 프록시만 세션을 열 수 있습니다).
InDenylist InDenylist principal(또는 대상 컨트랙트)이 전역 또는 컨트랙트 범위의 활성 DENYLIST_POLICY와 일치하면 revert됩니다.
EasAttestationRequired EasAttestationRequired EAS_POLICY가 요구하는 attestation을 principal이 보유하지 않으면 revert됩니다.
ExceededPeriodicVolume ExceededPeriodicVolume 주기 거래량 정책의 누적 금액과 value의 합이 설정된 상한을 초과하면 revert됩니다.

예제

PCL 프록시 훅에서 호출

preCall의 표준 호출자는 PCL 프록시 훅입니다. 반환된 sessionId를 저장했다가 delegatecall 종료 후 짝이 되는 postCall과 함께 사용합니다. 외부 dApp은 프록시를 직접 호출하며, 훅 배선은 노출되지 않습니다.

// Excerpt from PclProxyHook.sol — external dApps do NOT call preCall directly;
// the PCL-wrapped proxy calls it before delegatecalling its implementation.
address constant PCL = 0x1000000000000000000000000000000000000005;

function hookedDelegate(address addrForPolicy, address impl) internal {
    address principal = msg.sender;
    bytes32 sessionId = IPcl(PCL).preCall(
        addrForPolicy,   // proxy address = PCL policy key
        principal,       // actual EOA / AA caller
        msg.data,
        msg.value
    );

    (bool ok, bytes memory ret) = impl.delegatecall(msg.data);

    IPcl(PCL).postCall(sessionId, addrForPolicy, principal, msg.data, msg.value, ok);
    if (!ok) { assembly { revert(add(ret, 0x20), mload(ret)) } }
    assembly { return(add(ret, 0x20), mload(ret)) }
}

프록시 호출에서 PCL revert 디코딩

preCall이 거절하면 revert가 프록시를 통해 클라이언트까지 전파됩니다. IPcl ABI로 디코드하여 ReasonCode를 확인합니다.

import { createWalletClient, decodeErrorResult, http } from "viem";

try {
  await walletClient.writeContract({
    address: pclProxyAddress,
    abi: myTokenAbi,
    functionName: "transfer",
    args: [recipient, 10_000_000n * 10n ** 18n], // 10,000,000 OKRW
  });
} catch (err: any) {
  const decoded = decodeErrorResult({ abi: pclAbi, data: err.data });
  console.log("PCL ReasonCode:", decoded.errorName, decoded.args);
  // e.g. EasAttestationRequired { sender: 0x... }
}
ESC
검색어를 입력하세요