IPcl.registerPolicyTemplate / removePolicyTemplate

registerPolicyTemplate(
  string calldata templateId
) external
removePolicyTemplate(string calldata templateId) external

Chain-wide policy admin operations that add or remove one of the built-in PCL policy templates from the active registry. registerPolicyTemplate makes a template ID available for instantiation inside a PolicySet; removePolicyTemplate withdraws it. Only the address returned by IPcl.policyAdmin() may call these — other callers revert with Unauthorized(). Both calls, when made by the admin against the PCL precompile, bypass PCL policy evaluation via the admin recovery path, so they cannot be blocked by a misconfigured global policy that would otherwise reject the admin's own address.

Parameters

Name Type Required Description
templateId string The template identifier — one of the built-in IDs shipped with the chain (for example DENYLIST_POLICY, VOLUME_POLICY, PERIODIC_VOLUME_POLICY, EAS_POLICY, OKRW_EAS_TRANSFER_LIMIT_POLICY, OKRW_EAS_PERIODIC_VOLUME_LIMIT_POLICY, AGENT_OKRW_TRANSFER_LIMIT_POLICY). Registering an unknown ID reverts with InvalidPolicyTemplate(input); registering an already-registered ID reverts with DuplicatedPolicyTemplate(templateId); removing an unregistered ID reverts with PolicyTemplateNotFound(templateId).

Returns

Type: void

No return value. Success emits PolicyTemplateRegistered(templateId) or PolicyTemplateRemoved(templateId).

Errors

Code Name Description
Unauthorized Unauthorized Reverts when the caller is not the address returned by IPcl.policyAdmin().
InvalidPolicyTemplate InvalidPolicyTemplate Reverts when templateId does not match any built-in template shipped with the chain. Encoded as InvalidPolicyTemplate(bytes input).
DuplicatedPolicyTemplate DuplicatedPolicyTemplate Reverts on registerPolicyTemplate when the template is already in the active registry. Encoded as DuplicatedPolicyTemplate(string templateId).
PolicyTemplateNotFound PolicyTemplateNotFound Reverts on removePolicyTemplate when the template is not currently registered. Encoded as PolicyTemplateNotFound(string templateId). This same error surfaces at policy evaluation time if an existing PolicySet references a template that was subsequently removed — the removal itself is no longer blocked by outstanding consumers, so stale references are surfaced lazily against the offending transaction rather than eagerly against the admin.

Examples

Register a template as the policy admin

The call must originate from the current policyAdmin() address. Because the admin is calling one of the four PCL control-plane selectors on the PCL precompile, the transaction bypasses PCL policy evaluation and cannot be blocked by a global policy that would otherwise reject the admin's address.

import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";

const PCL = "0x1000000000000000000000000000000000000005" as const;
const pclAbi = [
  { type: "function", name: "registerPolicyTemplate", stateMutability: "nonpayable",
    inputs: [{ name: "templateId", type: "string" }], outputs: [] },
  { type: "function", name: "removePolicyTemplate", stateMutability: "nonpayable",
    inputs: [{ name: "templateId", type: "string" }], outputs: [] },
] as const;

const admin = createWalletClient({
  account: privateKeyToAccount(process.env.POLICY_ADMIN_KEY as `0x${string}`),
  transport: http("https://rpc-testnet.maroo.io"),
});

await admin.writeContract({
  address: PCL,
  abi: pclAbi,
  functionName: "registerPolicyTemplate",
  args: ["EAS_POLICY"],
});

Removing a template no longer checks for consumers

Removing a template is now a pure registry operation: it does not scan for contracts or global policies that reference the template. Any PolicySet left pointing at a removed template will fail at evaluation time with PolicyTemplateNotFound against the caller whose transaction triggered the check, not against the admin who performed the removal.

// Previously this could revert with `PolicyTemplateInUse` when a contract
// policy or the global config still referenced the template. That check has
// been removed; the call succeeds as long as the template is currently
// registered and the caller is the policy admin.
await admin.writeContract({
  address: PCL,
  abi: pclAbi,
  functionName: "removePolicyTemplate",
  args: ["VOLUME_POLICY"],
});

// Outstanding `PolicySet` entries that still reference "VOLUME_POLICY" will
// now cause the *user transaction* they gate to revert with
// `PolicyTemplateNotFound("VOLUME_POLICY")` when PCL evaluates it. The admin
// is expected to clean up (or re-register) the template before it removes it.
ESC
Type to search