IPcl.contractPolicies / removeContractPolicies

contractPolicies(
  address contractAddress
) external view returns (ContractPolicyConfig memory);
removeContractPolicies(address contractAddress) external;

Two operations against the contract-scoped policy binding. contractPolicies(address) is a view returning the currently bound ContractPolicyConfig (or a zeroed struct if none is bound). removeContractPolicies(address) clears the PolicySet[] on a PCL-wrapped proxy — it does NOT remove the contract-admin binding itself, so the admin retains authority to re-attach policies later via changeContractPolicies. Two guardrails: (1) only the current contract admin can remove; (2) policy-aware precompiles (addresses listed in PclParams.PolicyAwarePrecompiles) cannot be cleared this way — the call reverts with CannotEmpty("policy-aware precompile policies"). To relax rules on a policy-aware precompile, use changeContractPolicies with a permissive PolicySet instead.

Parameters

Name Type Required Description
contractAddress address Target contract. For the view, any address is acceptable (unbound targets return a zeroed struct). For removal, must be a PCL-wrapped proxy — policy-aware precompile addresses revert.

Returns

Type: ContractPolicyConfig | void

contractPolicies returns ContractPolicyConfig_contract, admin, and policies. removeContractPolicies returns nothing; success emits ContractPoliciesRemoved(contractAddress).

Errors

Code Name Description
Unauthorized Unauthorized Applies to removeContractPolicies. Reverts when msg.sender is not the target's current contract admin.
CannotEmpty CannotEmpty Applies to removeContractPolicies. Reverts with CannotEmpty("policy-aware precompile policies") when contractAddress is one of the policy-aware precompiles from PclParams.PolicyAwarePrecompiles — these targets must always retain at least one active PolicySet.
PclProxyNotRegistered PclProxyNotRegistered Applies to removeContractPolicies. Reverts when the target is not a PCL-wrapped proxy (and is not a policy-aware precompile, which is caught earlier by CannotEmpty).

Examples

Read the current binding via viem

Returns a fully populated ContractPolicyConfig when the target has a binding; otherwise every field is zero.

import { createPublicClient, http } from "viem";

const PCL = "0x1000000000000000000000000000000000000005" as const;
// TODO: replace with the real proxy address.
const PROXY = "0x8F3ac2B1d9E74c05A6B18FE27Dc4913e5A0F7b62" as const;

const publicClient = createPublicClient({ transport: http("https://rpc-testnet.maroo.io") });
const cfg = await publicClient.readContract({
  address: PCL,
  abi: pclAbi,
  functionName: "contractPolicies",
  args: [PROXY],
});
console.log(cfg.admin, cfg.policies.length);

Refuse to clear policies on a policy-aware precompile

removeContractPolicies is intentionally blocked on policy-aware precompiles so the chain never runs one with a missing policy set. Use changeContractPolicies to submit a new (possibly permissive) PolicySet instead.

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

const PCL = "0x1000000000000000000000000000000000000005" as const;
// Privacy precompile — a policy-aware precompile on Maroo.
const PRIVACY = "0x100000000000000000000000000000000000000b" as const;

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

try {
  await wallet.writeContract({
    address: PCL,
    abi: pclAbi,
    functionName: "removeContractPolicies",
    args: [PRIVACY],
  });
} catch (err: any) {
  const decoded = decodeErrorResult({ abi: pclAbi, data: err.data });
  // decoded.errorName === "CannotEmpty"
  // decoded.args      === ["policy-aware precompile policies"]
  console.error("cannot clear policies on a policy-aware precompile:", decoded.args[0]);
}
ESC
Type to search