IPcl.changeContractPolicies
changeContractPolicies(ContractPolicyConfig calldata policy) external 대상 주소의 ContractPolicyConfig를 upsert합니다. 대상은 deployPclProxy로 배포한 PCL 등록 프록시이거나, 바이너리가 지원하는 정책 인식 프리컴파일이어야 합니다. 정책 인식 프리컴파일은 현재 0x100000000000000000000000000000000000000b의 Privacy 프리컴파일 하나입니다. 특정 대상에 대한 최초 호출에서는 msg.sender가 누구든 가능하며, 페이로드의 admin이 이후 게이트키퍼가 됩니다. 이후 호출에서는 msg.sender가 저장된 현재 admin과 같아야 하고, 페이로드의 새 admin 값이 정책 교체와 함께 원자적으로 이전 값을 대체합니다. 정책 인식 프리컴파일에 빈 policies 배열을 전달하는 호출은 거절됩니다. 해당 대상은 항상 최소 하나 이상의 PolicySet을 유지해야 합니다. 일반 PCL 프록시는 빈 policies 배열을 허용하며, 이는 컨트랙트 범위 규칙이 없는 상태와 같습니다. 체인 전역 policyAdmin은 저장된 컨트랙트 admin과 우연히 같은 주소가 아닌 이상 이 설정을 변경할 수 없습니다.
파라미터
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
policy | ContractPolicyConfig | ✓ | 새 설정 페이로드입니다. _contract는 대상 주소(등록된 PCL 프록시 또는 정책 인식 프리컴파일 주소)입니다. admin은 이 대상의 정책 설정에 대한 다음 게이트키퍼입니다. policies는 전체를 대체할 PolicySet[]입니다. _contract가 등록된 PCL 프록시도 아니고 정책 인식 프리컴파일도 아니면 PclProxyNotRegistered(contractAddress)로 revert됩니다. _contract가 정책 인식 프리컴파일이고 policies가 비어 있으면 CannotEmpty("policy-aware precompile policies")로 revert됩니다. |
반환값
void 반환 값이 없습니다. 성공 시 ContractPoliciesChanged(contractAddress, admin, policies) 이벤트를 발행합니다.
에러
| 코드 | 이름 | 설명 |
|---|---|---|
Unauthorized | Unauthorized | 대상에 이미 설정이 존재하고 msg.sender가 저장된 현재 admin이 아닐 때 revert됩니다. 체인 전역 policyAdmin도 이 검사를 우회하지 못합니다. |
PclProxyNotRegistered | PclProxyNotRegistered | _contract가 등록된 PCL 프록시도 아니고 정책 인식 프리컴파일도 아닐 때 revert됩니다. PclProxyNotRegistered(address contractAddress) 형태로 인코딩됩니다. |
CannotEmpty | CannotEmpty | 대상이 정책 인식 프리컴파일인데 policies가 빈 배열일 때 revert됩니다. CannotEmpty(string field) 형태이며 field 값은 policy-aware precompile policies입니다. 정책 인식 프리컴파일은 항상 최소 하나 이상의 PolicySet을 유지해야 합니다. |
InvalidAddress | InvalidAddress | _contract 또는 admin을 유효한 주소로 디코드할 수 없을 때 revert됩니다. IPrecompile의 InvalidAddress(string bad)를 상속합니다. |
PolicyTemplateNotFound | PolicyTemplateNotFound | policies의 어떤 PolicySet.templateId가 이 네트워크에 등록된 템플릿이 아닐 때 revert됩니다. PolicyTemplateNotFound(string templateId) 형태로 인코딩됩니다. |
예제
PCL 래핑 ERC20 프록시에 denylist 정책 바인딩
PCL 등록 프록시에 대한 표준 사용 예시입니다. msg.sender는 이전 설정에서 저장된 admin과 같아야 하며, 이 프록시에 대한 최초 호출이면 누구든 가능합니다.
import { createWalletClient, http, encodeAbiParameters, toHex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
const PCL = "0x1000000000000000000000000000000000000005" as const;
const wallet = createWalletClient({
account: privateKeyToAccount(process.env.ADMIN_KEY as `0x${string}`),
transport: http("https://rpc-testnet.maroo.io"),
});
// TODO: replace with the real proxy and admin addresses before production.
const proxyAddress = "0x8F3ac2B1d9E74c05A6B18FE27Dc4913e5A0F7b62";
const adminAddress = "0x2c7f09B81a6D3FF1e5A0d4c6bC2a8f7E19dc3a4B";
const denylistBytes = encodeAbiParameters(
[{ type: "address[]", name: "addresses" }],
[[
"0x5aB7c1e40b8dA46f9c7e29D3fA614e97b8f0Ac21",
"0x6bC8d2a03e91FfA5b8c4E0F3Bd7A0E15C24bDa8E",
]],
);
await wallet.writeContract({
address: PCL,
abi: pclAbi,
functionName: "changeContractPolicies",
args: [{
_contract: proxyAddress,
admin: adminAddress,
policies: [{
templateId: "DENYLIST_POLICY",
policy: denylistBytes,
selector: toHex("", { size: 0 }),
}],
}],
}); Privacy 프리컴파일에 정책 세트 부착 (정책 인식 프리컴파일)
정책 인식 프리컴파일은 PCL 프록시와 동일한 진입점을 사용하지만, 대상 주소가 프리컴파일 주소 자체입니다. 빈 정책 세트는 거절되므로, 규칙을 회전할 때는 정책을 비운 뒤 다시 추가하는 대신 새로운 비어 있지 않은 PolicySet[]을 제출합니다.
import { encodeAbiParameters, toHex } from "viem";
const PCL = "0x1000000000000000000000000000000000000005" as const;
const PRIVACY = "0x100000000000000000000000000000000000000b" as const;
// TODO: replace with the real privacy-admin multisig before production.
const privacyAdmin = "0x2c7f09B81a6D3FF1e5A0d4c6bC2a8f7E19dc3a4B";
// Example: a DENYLIST_POLICY applied to every Privacy call.
const denylistBytes = encodeAbiParameters(
[{ type: "address[]", name: "addresses" }],
[["0x5aB7c1e40b8dA46f9c7e29D3fA614e97b8f0Ac21"]],
);
await wallet.writeContract({
address: PCL,
abi: pclAbi,
functionName: "changeContractPolicies",
args: [{
_contract: PRIVACY,
admin: privacyAdmin,
policies: [{
templateId: "DENYLIST_POLICY",
policy: denylistBytes,
selector: toHex("", { size: 0 }),
}],
}],
});
// NOTE: passing an empty policies array here reverts with
// CannotEmpty("policy-aware precompile policies"). To rotate rules,
// always submit a non-empty replacement set. 빈 정책으로 호출 시 CannotEmpty revert 디코드
revert 데이터는 CannotEmpty(string field) selector로 ABI 인코딩되며, 페이로드로 PCL의 다른 빈 필드 위반과 구분됩니다.
import { decodeErrorResult } from "viem";
try {
await wallet.writeContract({
address: PCL,
abi: pclAbi,
functionName: "changeContractPolicies",
args: [{
_contract: PRIVACY,
admin: privacyAdmin,
policies: [], // empty — will revert for policy-aware precompiles
}],
});
} catch (err: any) {
if (err?.data) {
const decoded = decodeErrorResult({ abi: pclAbi, data: err.data });
// decoded.errorName === "CannotEmpty"
// decoded.args[0] === "policy-aware precompile policies"
console.error(`changeContractPolicies reverted: ${decoded.errorName}`, decoded.args);
} else {
throw err;
}
}