> ## Documentation Index
> Fetch the complete documentation index at: https://base-a060aa97-roethke-b20-upgrade-pages.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# IPolicyRegistry.createCompositePolicy

> Creates a new composite policy that combines existing simple policies under a UNION or INTERSECT logic gate.

## Signature

```solidity IPolicyRegistry.sol theme={null}
function createCompositePolicy(address admin, PolicyType policyType, uint64[] calldata childPolicyIds) external returns (uint64 newPolicyId);
```

| Field | Value |
| - | - |
| Selector | `0x6fdd1491` |
| Canonical signature | `createCompositePolicy(address,uint8,uint64[])` |

## Description

Creates a composite policy that combines two to four existing simple policies (`ALLOWLIST` or `BLOCKLIST`) under a single logic gate:

| `policyType` | Authorized when |
| - | - |
| `UNION` | Any child authorizes the account |
| `INTERSECT` | Every child authorizes the account |

The registry stores references to the children, not a snapshot of their members. Every call to `isAuthorized` reads each child's current member set, so updates to a child policy are immediately visible through the composite.

Creation is permissionless. The `admin` you supply is the only address that can later call `updateComposite`, `stageUpdateAdmin`, or `renounceAdmin` on this policy.

On success, emits `PolicyCreated(newPolicyId, creator, policyType)`, `PolicyAdminUpdated(newPolicyId, address(0), admin)`, and `CompositePolicyUpdated(newPolicyId, creator, childPolicyIds)`.

## Parameters

| Name | Type | Description |
| - | - | - |
| `admin` | `address` | Initial admin authorized to update child policies and transfer or renounce administration. Cannot be `address(0)`. |
| `policyType` | `PolicyType` (`uint8`) | Must be `UNION` or `INTERSECT`. |
| `childPolicyIds` | `uint64[]` | IDs of existing simple policies to combine. Count must be in `[MIN_COMPOSITE_CHILD_POLICIES, MAX_COMPOSITE_CHILD_POLICIES]` (2–4). |

## Returns

| Name | Type | Description |
| - | - | - |
| `newPolicyId` | `uint64` | The newly assigned composite policy ID. |

## Reverts

| Error | Condition |
| - | - |
| `ZeroAddress()` | `admin` is `address(0)` |
| `IncompatiblePolicyType()` | `policyType` is not `UNION` or `INTERSECT` |
| `ChildPoliciesOutsideOfRange()` | `childPolicyIds.length` is outside `[MIN_COMPOSITE_CHILD_POLICIES, MAX_COMPOSITE_CHILD_POLICIES]` (2–4) |
| `PolicyNotFound()` | Any child policy ID does not exist in the registry |
| `InvalidChildPolicy(childPolicyId)` | Any child is not an existing simple policy (composites and built-in sentinels are not valid children) |
| Panic `0x11` | The policy ID counter has reached its maximum value |

## Access Control

Permissionless, any caller may create a composite policy.

## Example

```solidity Create a KYC-and-sanctions composite lines wrap expandable highlight={10} theme={null}
// 1. Create a KYC allowlist and a sanctions blocklist first.
uint64 kycId       = registry.createPolicy(admin, PolicyType.ALLOWLIST);
uint64 sanctionsId = registry.createPolicy(admin, PolicyType.BLOCKLIST);

// 2. Combine them: an account must be KYC'd AND not sanctioned.
uint64[] memory children = new uint64[](2);
children[0] = kycId;
children[1] = sanctionsId;

uint64 gateId = registry.createCompositePolicy(admin, PolicyType.INTERSECT, children);

// 3. Bind the composite to the token's transfer and mint scopes.
token.updatePolicy(B20Constants.TRANSFER_SENDER_POLICY, gateId);
token.updatePolicy(B20Constants.TRANSFER_RECEIVER_POLICY, gateId);
token.updatePolicy(B20Constants.MINT_RECEIVER_POLICY, gateId);
```

<Note>
  Updating a child policy's membership (via `updateAllowlist` or `updateBlocklist`) takes effect on the next `isAuthorized` call through any composite that references it. No second `updateComposite` is needed on the token.
</Note>
