Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/circlefin/evm-cctp-contracts/llms.txt

Use this file to discover all available pages before exploring further.

Denylistable Role

The Denylistable contract provides denylist management capabilities for CCTP V2 contracts. It allows designated denylister addresses to add or remove accounts from a denylist, preventing them from participating in cross-chain transfers. Source: Denylistable.sol
Denylistable is a V2-only feature. V1 contracts do not support denylisting.

Overview

Denylistable extends Ownable2Step and provides:
  • A designated denylister role that can manage the denylist
  • Functions to add and remove addresses from the denylist
  • A modifier to check if an address is denylisted
  • Events for tracking denylist changes
This role is used by TokenMessengerV2 to enforce compliance and prevent sanctioned addresses from using CCTP.

State Variables

_denylister

address internal _denylister;
The address with permission to add or remove accounts from the denylist.

_denylisted

mapping(address => uint256) internal _denylisted;
Maps addresses to their denylist status (1 = denylisted, 0 = not denylisted). Uses uint256 instead of bool for gas optimization.

Events

DenylisterChanged

Emitted when the denylister address is updated.
event DenylisterChanged(
    address indexed oldDenylister,
    address indexed newDenylister
);

Denylisted

Emitted when an account is added to the denylist.
event Denylisted(address indexed account);

UnDenylisted

Emitted when an account is removed from the denylist.
event UnDenylisted(address indexed account);

Functions

updateDenylister

Updates the denylister address. Only callable by the contract owner.
function updateDenylister(address newDenylister) external onlyOwner;
Parameters:
  • newDenylister (address): The address of the new denylister
Requirements:
  • Caller must be the contract owner
  • newDenylister must not be the zero address
Reference: src/roles/v2/Denylistable.sol:71

addToDenylist

Adds an account to the denylist. Only callable by the denylister.
function addToDenylist(address account) external onlyDenylister;
Parameters:
  • account (address): The address to add to the denylist
Requirements:
  • Caller must be the denylister
  • account must not already be denylisted
Emits: Denylisted event Reference: src/roles/v2/Denylistable.sol:87

removeFromDenylist

Removes an account from the denylist. Only callable by the denylister.
function removeFromDenylist(address account) external onlyDenylister;
Parameters:
  • account (address): The address to remove from the denylist
Requirements:
  • Caller must be the denylister
  • account must currently be denylisted
Emits: UnDenylisted event Reference: src/roles/v2/Denylistable.sol:101

isDenylisted

Checks if an address is on the denylist.
function isDenylisted(address account) external view returns (bool);
Parameters:
  • account (address): The address to check
Returns:
  • bool: true if the account is denylisted, false otherwise
Reference: src/roles/v2/Denylistable.sol:113

denylister

Returns the current denylister address.
function denylister() external view returns (address);
Returns:
  • address: The address of the current denylister
Reference: src/roles/v2/Denylistable.sol:121

Modifiers

onlyDenylister

Restricts function access to the denylister address only.
modifier onlyDenylister();
Reverts with “Caller is not the denylister” if the caller is not the denylister.

notDenylisted

Checks that an address is not on the denylist.
modifier notDenylisted(address account);
Parameters:
  • account (address): The address to check
Reverts with “Account is denylisted” if the address is on the denylist.

Usage in TokenMessengerV2

TokenMessengerV2 uses Denylistable to prevent denylisted addresses from:
  • Depositing USDC for burn
  • Receiving minted USDC on the destination chain

Deposit Validation

function depositForBurn(
    uint256 amount,
    uint32 destinationDomain,
    bytes32 mintRecipient,
    address burnToken,
    uint256 maxFee,
    uint32 minFinalityThreshold,
    bytes32 destinationCaller
) external notDenylisted(msg.sender) returns (uint64) {
    // Deposit logic...
}

Mint Recipient Validation

Before minting, TokenMessengerV2 checks that the mint recipient is not denylisted:
bytes32 mintRecipient = burnMessage.mintRecipient();
address mintRecipientAddress = mintRecipient.toAddress();

require(
    !isDenylisted(mintRecipientAddress),
    "Mint recipient is denylisted"
);

Configuration Example

Setting up denylist management:
// Deploy TokenMessengerV2 with denylister role
address denylister = 0x123...; // Compliance team address

// Update denylister (owner only)
tokenMessengerV2.updateDenylister(denylister);

// Add address to denylist (denylister only)
address sanctionedAddress = 0x456...;
tokenMessengerV2.addToDenylist(sanctionedAddress);

// Check if address is denylisted
bool isDenied = tokenMessengerV2.isDenylisted(sanctionedAddress);
// Returns: true

// Remove from denylist when appropriate
tokenMessengerV2.removeFromDenylist(sanctionedAddress);

Security Considerations

The denylister role has significant power to block addresses from using CCTP. This role should be assigned to trusted compliance personnel or multi-sig wallets.

Access Control

  • Owner Control: Only the contract owner can change the denylister address
  • Denylister Independence: The denylister operates independently from the owner for day-to-day denylist management
  • Two-Step Ownership: Inherits secure ownership transfer from Ownable2Step

Best Practices

  1. Multi-Sig Denylister: Use a multi-sig wallet as the denylister to prevent single-point-of-failure
  2. Monitoring: Emit and monitor all denylist events for transparency
  3. Regular Reviews: Periodically review the denylist and remove addresses when appropriate
  4. Emergency Procedures: Have documented procedures for urgent denylist additions
  5. Legal Compliance: Ensure denylist operations comply with applicable regulations

Gas Optimization

The contract uses uint256 constants (_TRUE = 1, _FALSE = 0) instead of booleans for the denylist mapping to optimize gas costs during storage operations.
  • TokenMessengerV2 - Implements Denylistable for deposit and mint protection
  • Ownable2Step - Base contract providing secure ownership management
  • V2 Overview - Learn more about V2 features including denylist

Comparison with V1

V1 contracts do not have denylist functionality. This is a new feature in V2 designed to enhance compliance capabilities:
FeatureV1V2
Denylist Support❌ No✅ Yes
Compliance Role❌ No✅ Denylister
Address Blocking❌ No✅ Yes
Granular Control❌ No✅ Yes

Migration Considerations

When migrating from V1 to V2, you’ll need to:
  1. Designate a denylister address
  2. Import any existing blocklists from external sources
  3. Update client code to handle denylist-related errors
  4. Implement monitoring for denylist events
See the V2 Migration Guide for complete migration instructions.

Build docs developers (and LLMs) love