IPcl.postCall

postCall(bytes32 sessionId, address contractAddress, address principal, bytes calldata data, uint256 value, bool workable) external returns (bytes memory)

프록시가 구현체에 대한 delegatecall을 마친 뒤, 짝이 되는 preCall이 연 PCL 세션을 닫습니다. postCall은 구현체 내부에서 발생한 전송 로그 델타를 검사해 주기 거래량 누적을 기록하고, AGENT_OKRW_TRANSFER_LIMIT_POLICY, OKRW_EAS_TRANSFER_LIMIT_POLICY 같은 사후 정책을 평가합니다. workablefalse이면(구현체가 이미 revert된 경우) 사후 정책 평가, 거래량 기록, 로그 마킹, 이벤트 발행을 모두 건너뜁니다.

파라미터

이름 타입 필수 설명
sessionId bytes32 짝이 되는 preCall이 반환한 식별자입니다. 사전 로그 오프셋과 네이티브 전송 수집기 스냅숏을 조회하는 데 사용합니다.
contractAddress address PCL 정책 조회 키로 사용되는 프록시 주소입니다. preCall에 전달한 값과 일치해야 합니다.
principal address preCall에서 전파된 호출 발신자입니다. denylist, 에이전트 전송 한도 등 principal 범위 정책에 사용합니다.
data bytes preCall에 전달한 값과 동일한, 구현체로 전달된 원본 내부 calldata입니다.
value uint256 호출에 첨부된 네이티브 값(aokrw 단위)입니다. 호출이 성공했을 때 주기 네이티브 거래량 기록에 사용합니다.
workable bool 구현체 delegatecall이 성공적으로 반환되면 true, revert되면 false입니다. false이면 PCL이 사후 처리(부기)를 모두 건너뛰어 revert된 호출의 부작용이 남지 않습니다.

반환값

타입: bytes

빈 bytes를 반환합니다. 호출자(프록시 훅)는 delegatecall의 원본 반환 데이터 또는 revert 데이터를 전파하며, 이 반환값은 사용하지 않습니다.

에러

코드 이름 설명
Unauthorized Unauthorized 직접 호출자가 허용된 PCL 프록시 진입점이 아니면 revert됩니다.
ExceededPeriodicVolume ExceededPeriodicVolume 사후 전송 누적으로 주기 거래량 정책이 상한을 초과하면 revert됩니다.
ExceededAgentTransferLimit ExceededAgentTransferLimit 호출 내부에서 관찰된 OKRW 전송이 AGENT_OKRW_TRANSFER_LIMIT_POLICY의 단일 전송 상한을 초과하면 revert됩니다.
VolumeAboveMaxLimit VolumeAboveMaxLimit 호출 내부 전송이 OKRW_EAS_TRANSFER_LIMIT_POLICY 또는 VOLUME_POLICY의 최댓값을 초과하면 revert됩니다.

예제

PCL 프록시 훅에서 호출

프록시 훅은 구현체가 revert된 경우에도 반드시 postCall을 호출해 세션을 정상 종료합니다. workable 플래그는 사후 정책을 실행할지 단축 평가할지를 PCL에 알려줍니다.

// Excerpt from PclProxyHook.sol — external dApps do NOT call postCall directly.
address constant PCL = 0x1000000000000000000000000000000000000005;

function hookedDelegate(address addrForPolicy, address impl) internal {
    address principal = msg.sender;
    bytes32 sessionId = IPcl(PCL).preCall(addrForPolicy, principal, msg.data, msg.value);

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

    // `ok` is forwarded as `workable`; when false, PCL skips post-call bookkeeping.
    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)) }
}

사후 revert 디코딩

PCL은 사후 거절도 사전 거절과 동일한 revert 경로로 노출합니다. 어느 쪽에서 발동했는지와 무관하게 클라이언트는 IPcl ABI로 디코드합니다.

import { decodeErrorResult } from "viem";

// A transfer that fits pre-call policy but pushes the daily accumulator over its cap
// will succeed inside the implementation and then revert in postCall.
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(decoded.errorName, decoded.args);
  // e.g. ExceededPeriodicVolume { maxLimit, value, resetAt }
}
ESC
검색어를 입력하세요