> ## Documentation Index
> Fetch the complete documentation index at: https://base-a060aa97-docs-sync-code-change-91427ab.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# IB20.updatePolicy

> Binds a Policy Registry policy ID to a policy scope on a B20 token.

## Signature

```solidity IB20.sol theme={null}
function updatePolicy(bytes32 policyScope, uint64 newPolicyId) external;
```

| Field               | Value                          |
| ------------------- | ------------------------------ |
| Selector            | `0xadf9c4ea`                   |
| Canonical signature | `updatePolicy(bytes32,uint64)` |

## Description

Binds `newPolicyId` to `policyScope`. Takes effect immediately: the next operation that consults that scope calls `isAuthorized(newPolicyId, account)` on the Policy Registry. Emits `PolicyUpdated`.

Until a scope is updated it holds `0` (`ALWAYS_ALLOW`), so the check passes for every address.

## Parameters

| Parameter     | Description                                                                                                                                                                                                       |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `policyScope` | The scope slot to update. Must be a scope this token recognizes.                                                                                                                                                  |
| `newPolicyId` | The policy ID to assign. Must be a built-in sentinel (`ALWAYS_ALLOW`, `ALWAYS_BLOCK`), an existing registry policy, or an inverted ID whose base policy exists. The token treats the value as an opaque `uint64`. |

## Reverts

| Error                                | Condition                                                                                                                                                                        |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AccessControlUnauthorizedAccount`   | Caller does not hold `DEFAULT_ADMIN_ROLE`.                                                                                                                                       |
| `UnsupportedPolicyType(policyScope)` | `policyScope` is not a slot this token supports.                                                                                                                                 |
| `PolicyNotFound(newPolicyId)`        | `newPolicyId` is not a built-in sentinel and does not exist in the registry. An inverted ID is valid when its base exists, because `policyExists` strips bit 63 before checking. |

## Access Control

`DEFAULT_ADMIN_ROLE` gates this call. During token creation, `initCalls` may bind policies in the same transaction; those calls bypass the role gate.

## Policy Scopes

The recognized scopes and the accounts they check are:

| Scope                      | Checked account                                            | Denies when `isAuthorized` is |
| -------------------------- | ---------------------------------------------------------- | ----------------------------- |
| `TRANSFER_SENDER_POLICY`   | `from`                                                     | `false`                       |
| `TRANSFER_RECEIVER_POLICY` | `to`                                                       | `false`                       |
| `TRANSFER_EXECUTOR_POLICY` | `msg.sender` (on `transferFrom` when `msg.sender != from`) | `false`                       |
| `MINT_RECEIVER_POLICY`     | `to`                                                       | `false`                       |
| `SEIZE_EXEMPT_POLICY`      | `from`                                                     | `true`                        |
| `SEIZE_RECEIVER_POLICY`    | `to`                                                       | `false`                       |

Transfer scopes are skipped on factory `initCalls` transfers. `MINT_RECEIVER_POLICY` is always checked, including factory `initCalls` mints. `SEIZE_EXEMPT_POLICY` unset (`ALWAYS_ALLOW`) means no account is seizable.

## Inverted Policy IDs

Bit 63 of a `uint64` policy ID is the invert (NOT) flag. Passing an inverted ID to `updatePolicy` is valid as long as the base policy (the ID with bit 63 cleared) exists in the registry. The token stores and passes the full `uint64` — including the invert bit — to `isAuthorized`, which returns the opposite of the base policy's decision. If the base does not exist at evaluation time, `isAuthorized` returns `false` (fail-closed).

Use `invertedPolicyId(policyId)` on the Policy Registry to toggle the bit rather than computing it manually.

## Example

```solidity Usage Example theme={null}
IB20(token).updatePolicy(B20Constants.TRANSFER_RECEIVER_POLICY, policyId);
```

```solidity Inverted Policy Example theme={null}
uint64 notExcluded = IPolicyRegistry(registry).invertedPolicyId(exclusionId);
IB20(token).updatePolicy(B20Constants.TRANSFER_RECEIVER_POLICY, notExcluded);
```

The same policy ID can be bound to more than one scope and to more than one token. Updating membership in the registry policy is visible immediately on every scope and token that references it; no second `updatePolicy` call is needed.
