IPcl.changeContractPolicies
changeContractPolicies(ContractPolicyConfig calldata policy) external 컨트랙트의 정책 설정 전체를 교체하며, 동일한 호출에서 admin 권한을 이전할 수도 있습니다. 호출자는 policy._contract의 현재 admin이어야 합니다. 성공 시 저장된 PolicySet[]은 policy.policies로 완전히 교체되고 admin 바인딩은 policy.admin으로 설정됩니다. 현재 admin을 유지하려면 policy.admin에 동일한 주소를 전달합니다. 권한을 이전하려면 새 admin의 주소를 전달합니다. 이것이 지원되는 유일한 admin 이전 경로이며, 별도의 transfer 메서드는 없습니다.
파라미터
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
policy | ContractPolicyConfig | ✓ | 교체할 전체 설정입니다. _contract는 대상 컨트랙트를 지정합니다(기존 설정이 있어야 합니다). admin은 이 호출 이후의 admin이 될 주소입니다. 현재 admin과 동일한 주소를 지정하면 권한이 유지되고, 다른 주소를 지정하면 권한이 이전됩니다. policies는 새로운 완전한 PolicySet[] 배열이며, 병합이나 delta가 아닌 통째 교체입니다. |
반환값
타입:
void 반환값이 없습니다. 실패 시 revert됩니다.
에러
| 코드 | 이름 | 설명 |
|---|---|---|
Unauthorized | Unauthorized | 호출자가 policy._contract의 현재 admin이 아니면 revert됩니다. |
PolicyNotRegistered | PolicyNotRegistered | policy._contract에 기존 정책 설정이 없으면 revert됩니다. 최초 등록에는 registerContractPolicies를 사용합니다. |
InvalidAddress | InvalidAddress | _contract 또는 admin을 유효한 체인 측 계정으로 정규화할 수 없으면 revert됩니다. |
UnknownPolicyType | UnknownPolicyType | policies의 PolicySet.templateId 중 어느 하나라도 이 네트워크에 등록된 정책 템플릿과 일치하지 않으면 revert됩니다. |
InvalidParameter | InvalidParameter | PolicySet.policy 바이트가 템플릿의 예상 파라미터 struct로 ABI 디코드되지 않으면 revert됩니다. |
예제
admin을 유지한 채 정책 갱신
표준 정책 갱신 흐름입니다. 현재 admin이 교체용 PolicySet[]을 제출하고 admin에 자기 주소를 그대로 넣어 권한을 유지합니다.
import { createWalletClient, http, encodeAbiParameters } from "viem";
import { privateKeyToAccount } from "viem/accounts";
const PCL = "0x1000000000000000000000000000000000000005";
const tokenAddress = "0x1234567890123456789012345678901234567890"; // replace before production
const currentAdmin = "0xAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAaAa"; // replace before production
const denylistBytes = encodeAbiParameters(
[{ type: "address[]", name: "addresses" }],
[["0xBbbBBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBbBb"]],
);
const wallet = createWalletClient({
account: privateKeyToAccount(process.env.ADMIN_KEY as `0x${string}`),
transport: http(process.env.MAROO_RPC),
});
await wallet.writeContract({
address: PCL,
abi: pclAbi,
functionName: "changeContractPolicies",
args: [{
_contract: tokenAddress,
admin: currentAdmin, // same address → no handover
policies: [{
templateId: "DENYLIST_POLICY",
policy: denylistBytes,
selector: "0x",
}],
}],
}); 동일한 호출에서 admin 권한 이전
권한 이전 흐름입니다. 현재 admin이 admin에 다른 주소를 지정합니다. 트랜잭션이 확정되면 새 admin만이 해당 컨트랙트의 정책을 변경하거나 제거할 수 있습니다. 권한 이전과 정책 교체는 동일한 호출에서 원자적으로 이루어집니다.
// Called by the CURRENT admin. After this transaction lands, `newAdmin`
// becomes the sole address able to call changeContractPolicies /
// removeContractPolicies for tokenAddress.
const newAdmin = "0xCcCcCcCcCcCcCcCcCcCcCcCcCcCcCcCcCcCcCcCc"; // replace before production
await wallet.writeContract({
address: PCL,
abi: pclAbi,
functionName: "changeContractPolicies",
args: [{
_contract: tokenAddress,
admin: newAdmin, // handover: authority transfers to newAdmin
policies: existingPolicySets, // keep policies as-is, or replace at the same time
}],
});
// A subsequent call from the old admin would now revert with Unauthorized. 정책 하나만 조정할 때 read-modify-write
changeContractPolicies는 PolicySet[] 전체를 교체하므로, 반드시 현재 설정을 먼저 읽어 로컬에서 배열을 재구성한 뒤 제출합니다.
import { createPublicClient, http } from "viem";
const publicClient = createPublicClient({ transport: http(process.env.MAROO_RPC) });
// Read the current config first — the call is a wholesale replacement,
// so anything you omit gets dropped.
const current = await publicClient.readContract({
address: PCL,
abi: pclAbi,
functionName: "contractPolicies",
args: [tokenAddress],
});
// Rebuild the array with your edit; here we append a new PolicySet.
const nextPolicies = [...current.policies, additionalPolicySet];
await wallet.writeContract({
address: PCL,
abi: pclAbi,
functionName: "changeContractPolicies",
args: [{
_contract: tokenAddress,
admin: current.admin, // preserve current admin
policies: nextPolicies,
}],
});