# Configure a sender allowlist with AdvancedPoolHooks using Hardhat
Source: https://docs.chain.link/ccip/evm/tutorials/cross-chain-tokens/configure-sender-allowlist-advanced-pool-hooks-hardhat
Last Updated: 2026-05-05

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

## Guide Versions

- [Foundry](/ccip/evm/tutorials/cross-chain-tokens/configure-sender-allowlist-advanced-pool-hooks-foundry)

- [Hardhat](/ccip/evm/tutorials/cross-chain-tokens/configure-sender-allowlist-advanced-pool-hooks-hardhat)

CCIP 2.0 token pools support an optional [`AdvancedPoolHooks`](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-v2.0.0/chains/evm/contracts/pools/AdvancedPoolHooks.sol) contract being attached to them.

This contract can run certain checks:

1. before tokens are locked/burned (source chain)
2. before tokens are released/minted (destination chain)

If no hooks contract is attached, the token pool keeps its existing behavior.

This tutorial covers the **sender allowlist** use case: only approved addresses may initiate outbound transfers on the source chain. A sender not on the list reverts the source transaction with `SenderNotAllowed`. For the other capabilities, see the [AdvancedPoolHooks concept page](/ccip/concepts/cross-chain-token/advanced-pool-hooks) or [Enforce ACE policies on CCIP token transfers](/ccip/evm/tutorials/cross-chain-tokens/enforce-ace-policies-hardhat).

Hooks are enforced only when **both** of these aspects are configured:

- The token pool points to the `AdvancedPoolHooks` contract.
- The hooks contract authorizes that token pool as a caller.

Authorize the pool before attaching hooks so the first hook call does not revert. Hooks are configured **per token pool, per chain**, which means that:
you need to repeat this setup for any other pool where you want hooks enforced.

> **Note:** Remember. Your CCT token can be deployed on multiple chains, with each chain having its own token pool.

In this tutorial you will:

1. Review the current hooks state on your deployed token pool.
2. Send a baseline transfer (*with no hooks attached*). This should succeed.
3. Deploy an `AdvancedPoolHooks` contract with your deployer address on the allowlist.
4. Authorize the pool as a caller on the hooks contract and attach the hooks contract to the token pool.
5. Verify the hooks attachment, authorized callers, and allowlist state.
6. Remove your address from the allowlist.
7. Attempt a transfer (*expected to revert with `SenderNotAllowed(address)`*).
8. Detach the hooks contract.
9. Send a transfer again (*expected to succeed*).
10. Manage the allowlist over time (add, remove, and check addresses).

## Before You Begin

## 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.