# Enforce ACE policies on CCIP token transfers using Foundry
Source: https://docs.chain.link/ccip/evm/tutorials/cross-chain-tokens/enforce-ace-policies-foundry
Last Updated: 2026-09-26

> For the complete documentation index, see [llms.txt](/llms.txt).

## Guide Versions

- [Foundry](/ccip/evm/tutorials/cross-chain-tokens/enforce-ace-policies-foundry)

- [Hardhat](/ccip/evm/tutorials/cross-chain-tokens/enforce-ace-policies-hardhat)

[`AdvancedPoolHooks`](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-v2.0.0/chains/evm/contracts/pools/AdvancedPoolHooks.sol) can forward each transfer to a [Chainlink ACE](/ace) Policy Engine for evaluation before the source token pool locks or burns tokens (`preflightCheck`) and before the destination token pool releases or mints tokens (`postflightCheck`). If a policy rejects the call, the hook reverts and the transfer does not proceed.

This tutorial covers the **ACE policy enforcement** use case on a working CCT lane. For the sender allowlist use case instead, see [Configure a sender allowlist with AdvancedPoolHooks](/ccip/evm/tutorials/cross-chain-tokens/configure-sender-allowlist-advanced-pool-hooks-foundry). For how the hook, engine, extractor, and policies fit together, read the [AdvancedPoolHooks concept page](/ccip/concepts/cross-chain-token/advanced-pool-hooks).

In this tutorial you will:

1. Reuse an existing working CCT lane between Ethereum Sepolia and Arbitrum Sepolia.
2. Deploy `AdvancedPoolHooks` on both chains with their Policy Engine addresses set, and attach them to both token pools.
3. Point the hooks at their Policy Engines with `setPolicyEngine` when the engine was not set at deployment or needs to change.
4. Complete the ACE Platform setup: target detection, contract-type assignment, policy creation, and extractor mappings.
5. Demonstrate a source `preflightCheck` rejection using the `from` parameter.
6. Demonstrate a successful unrestricted transfer.
7. Demonstrate a destination `postflightCheck` rejection using the `to` parameter.
8. Update the destination policy and manually execute the failed message.

> **NOTE: What this tutorial does not repeat**
>
> Token and pool deployment, admin registration, and lane configuration: complete a registration tutorial first (see&#x20;
> [Confirm prerequisites](#confirm-prerequisites-addresses-and-permissions)).
>
> The ACE Platform workflow (engine creation, target detection, contract-type assignment, policy instances,
> protections, extractor mappings): follow&#x20;
> [Protect CCIP Token Pools with ACE](/ace/guides/policy-manager/ccip-token-pools) for each step.

## Before You Begin

> **CAUTION: ACE Beta access required**
>
> ACE is currently available through the Beta program. [Contact us](https://chain.link/contact) to request
> access or schedule a demo. After ACE is enabled for your organization, complete the [ACE account
> setup](/ace/getting-started/account-setup) before continuing.

## Tutorial

> **CAUTION: Educational Example Disclaimer**
>
> This page includes an educational example to use a Chainlink system, product, or service and is provided to
> demonstrate how to interact with Chainlink's systems, products, and services to integrate them into your own. This
> template is provided "AS IS" and "AS AVAILABLE" without warranties of any kind, it has not been audited, and it may be
> missing key checks or error handling to make the usage of the system, product or service more clear. Do not use the
> code in this example in a production environment without completing your own audits and application of best practices.
> Neither Chainlink Labs, the Chainlink Foundation, nor Chainlink node operators are responsible for unintended outputs
> that are generated due to errors in code.