IPcl.pclProxy

pclProxy(address proxy) external view returns (PclProxyEntry memory)

Returns the on-chain registry entry for a PCL-wrapped proxy address. The PclProxyEntry tuple contains the proxy variant (kind), the currently-bound policy admin (admin), and the registered proxy address (proxy). If proxy is not registered, every field of the returned entry is zero (kind = Unspecified, admin = 0x0, proxy = 0x0) — the call does not revert. The admin field is a projection of the canonical contract-admin record: it is set the moment deployPclProxy runs and is kept in sync when a subsequent changeContractPolicies rotates the admin, so a client reading this view sees the current gatekeeper without a second query to contractPolicies.

Parameters

Name Type Required Description
proxy address The proxy address to look up in the PCL proxy registry. This is the address a user calls when transacting through the regulated path (not the underlying implementation address).

Returns

Type: PclProxyEntry

A tuple of (PclProxyKind kind, address admin, address proxy). kind is one of Unspecified | Transparent | UUPS | Beacon. admin is the address currently authorized to call changeContractPolicies and removeContractPolicies against this proxy. proxy is the registered proxy address itself, echoed back for convenience when iterating multiple entries client-side. When the address is not registered, all three fields are zero.

Examples

Read a proxy registry entry with viem

The view returns zero-valued fields for unregistered addresses; branch on kind === Unspecified (0) to detect that case rather than catching a revert.

import { createPublicClient, http } from "viem";

const PCL = "0x1000000000000000000000000000000000000005" as const;

const pclAbi = [{
  name: "pclProxy", type: "function", stateMutability: "view",
  inputs: [{ name: "proxy", type: "address" }],
  outputs: [{
    type: "tuple",
    components: [
      { name: "kind",  type: "uint8"   },
      { name: "admin", type: "address" },
      { name: "proxy", type: "address" },
    ],
  }],
}] as const;

const client = createPublicClient({ transport: http("https://rpc-testnet.maroo.io") });

// TODO: replace with the real proxy address before production.
const proxyAddress = "0x8f3aC2b1D9e74C05a6B18Fe27dC4913E5A0f7b62";

const entry = await client.readContract({
  address: PCL,
  abi: pclAbi,
  functionName: "pclProxy",
  args: [proxyAddress],
});

if (entry.kind === 0) {
  console.log("not a registered PCL proxy");
} else {
  const kindName = ["Unspecified", "Transparent", "UUPS", "Beacon"][entry.kind];
  console.log(`kind=${kindName} admin=${entry.admin} proxy=${entry.proxy}`);
}

Verify the caller of changeContractPolicies is still the registered admin

Because admin mirrors the contract-admin binding, on-chain automation can gate follow-up policy updates on the current admin without a second call to contractPolicies.

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;

import { IPcl, PclProxyEntry, PclProxyKind } from "@maroo-chain/contracts/precompiles/pcl/IPcl.sol";

contract AdminGuard {
    IPcl constant PCL = IPcl(0x1000000000000000000000000000000000000005);

    /// @notice Reverts unless `expectedAdmin` is currently the admin recorded
    ///         in the PCL proxy registry for `proxy`.
    function requireProxyAdmin(address proxy, address expectedAdmin) external view {
        PclProxyEntry memory entry = PCL.pclProxy(proxy);
        require(entry.kind != PclProxyKind.Unspecified, "not a registered PCL proxy");
        require(entry.admin == expectedAdmin, "admin rotated");
    }
}
ESC
Type to search