IPcl.postCall

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

Closes the PCL session opened by a matching preCall after the proxy's delegatecall to its implementation returns. postCall inspects the transfer log delta that occurred inside the implementation, records periodic-volume accumulation, and evaluates any post-call policy checks (e.g. AGENT_OKRW_TRANSFER_LIMIT_POLICY, OKRW_EAS_TRANSFER_LIMIT_POLICY). If workable is false (the implementation already reverted), post-call policy evaluation, volume recording, log marking, and event emission are all skipped.

Parameters

Name Type Required Description
sessionId bytes32 The identifier returned by the matching preCall. Used to look up the pre-call log offset and native-transfer collector snapshot.
contractAddress address The proxy address used as the PCL policy-lookup key. Must match the value passed to preCall.
principal address The originator of the call, propagated from preCall. Used for principal-scoped policies (denylist, agent transfer limit, etc.).
data bytes The original inner calldata forwarded to the implementation, matching the value passed to preCall.
value uint256 The native value (in aokrw) attached to the call. Used to record periodic native-volume when the call succeeded.
workable bool true when the implementation's delegatecall returned successfully, false when it reverted. When false, PCL skips all post-call bookkeeping so no side effects persist from a reverted call.

Returns

Type: bytes

Returns empty bytes. The caller (proxy hook) bubbles the delegatecall's original return data or revert data — not this return value.

Errors

Code Name Description
Unauthorized Unauthorized Reverts when the immediate caller is not an allowed PCL proxy entrypoint.
ExceededPeriodicVolume ExceededPeriodicVolume Reverts when the post-call transfer accumulation would push a periodic-volume policy above its cap.
ExceededAgentTransferLimit ExceededAgentTransferLimit Reverts when an AGENT_OKRW_TRANSFER_LIMIT_POLICY's per-transfer cap is breached by an OKRW transfer observed inside the call.
VolumeAboveMaxLimit VolumeAboveMaxLimit Reverts when an OKRW_EAS_TRANSFER_LIMIT_POLICY or VOLUME_POLICY's max is exceeded by an in-call transfer.

Examples

Invoked by the PCL proxy hook

The proxy hook always calls postCall — even when the implementation reverted — so the session is closed cleanly. The workable flag tells PCL whether to run post-call policies or short-circuit.

// 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)) }
}

Decoding a post-call revert

PCL surfaces post-call rejections through the same revert path as pre-call ones. Clients decode with the IPcl ABI regardless of which side fired.

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
Type to search