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
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]);
}