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.

Overview

This guide covers testing strategies for EVM CCTP Contracts, including unit tests, integration tests, linting, and static analysis.

Prerequisites

  • Foundry CLI installed (forge 0.2.0)
  • Git submodules initialized: git submodule update --init --recursive
  • Yarn installed: yarn install

Unit Tests

Running Tests

Run unit tests using the Foundry forge CLI:
forge test
Alternatively, run tests in a Docker container:
make test

Test Output

Successful test output:
[PASS] testDepositForBurn() (gas: 123456)
[PASS] testReceiveMessage() (gas: 234567)
Test result: ok. 42 passed; 0 failed; finished in 2.34s

Debug Logs

Control test verbosity using the -v flag to display logs and traces:

Verbosity Levels

FlagOutput LevelDescription
-vBasicShows test results
-vvDetailedShows console.log() statements
-vvvVerboseShows execution traces
-vvvvVery VerboseShows execution traces with stack
-vvvvvMaximumShows all execution details

Examples

Display console.log statements:
forge test -vv
Show full execution traces:
forge test -vvvv
Test specific contract:
forge test --match-contract MessageTransmitterTest -vv
Test specific function:
forge test --match-test testDepositForBurn -vvv

Adding Debug Logs

To use console.log() in your contracts, import the console library:
import "lib/forge-std/src/console.sol";

contract MyContract {
    function myFunction() public {
        console.log("Debug value:", someValue);
    }
}

Integration Tests

Integration tests run against a local Anvil test node and simulate full cross-chain scenarios.

Running Integration Tests

make anvil-test
This command:
  1. Starts an Anvil test node in a Docker container
  2. Deploys all contracts
  3. Runs integration test suite
  4. Cleans up resources

Example Integration Test

An example integration test is available in the anvil/ folder that demonstrates:
  • Deploying contracts to local testnet
  • Configuring cross-chain messaging
  • Executing full deposit and burn flow
  • Simulating attestation
  • Receiving messages on destination chain

Manual Integration Testing

Start Anvil manually for interactive testing:
# Start Anvil node
anvil

# In another terminal, deploy contracts
forge script scripts/v1/deploy.s.sol --rpc-url http://localhost:8545 --broadcast

# Run your tests
forge test --fork-url http://localhost:8545

Linting

Lint Solidity code to enforce style guidelines and catch common issues:
yarn lint
This checks all .sol files in the src/ and test/ directories.

Linting Configuration

Linting rules are defined in .solhint.json. Common checks include:
  • Code style and formatting
  • Best practice violations
  • Security anti-patterns
  • Gas optimization opportunities

Fixing Linting Issues

Some linting issues can be auto-fixed:
yarn lint:fix

Common Linting Rules

Naming Conventions:
// Bad
function MyFunction() public {}

// Good
function myFunction() public {}
Visibility Modifiers:
// Bad
function transfer() {}

// Good
function transfer() external {}
Import Organization:
// Good - imports at top, organized
import "./interfaces/IReceiver.sol";
import "./libraries/Message.sol";

Static Analysis

Run static analysis using Mythril to detect security vulnerabilities:

Analyzing Contracts

MessageTransmitter:
make analyze-message-transmitter
MessageTransmitterV2:
make analyze-message-transmitter-v2
TokenMessengerMinter:
make analyze-token-messenger-minter

Analyzing Individual Files

If Mythril is already installed:
myth -v4 analyze $FILE_PATH \
  --solc-json mythril.config.json \
  --solv 0.7.6
Example:
myth -v4 analyze src/MessageTransmitter.sol \
  --solc-json mythril.config.json \
  --solv 0.7.6
Static analysis can take several minutes to complete, especially for complex contracts.

Understanding Results

Mythril reports potential issues with severity levels:
  • High: Critical security vulnerabilities
  • Medium: Significant issues that should be addressed
  • Low: Minor issues or informational warnings

Continuous Integration

GitHub Actions automatically runs tests on every push and pull request.

CI Workflow

The workflow configuration is in .github/workflows/ci.yml and includes:
  1. Linting checks
  2. Unit tests
  3. Integration tests
  4. Code coverage reports

Viewing CI Results

Check CI status:
  1. Navigate to the repository on GitHub
  2. Click the “Actions” tab
  3. Select the workflow run to view details

Local CI Simulation

Run the same checks locally before pushing:
# Run all checks
yarn lint && forge test && make anvil-test

Security Scanning

Olympix AI Scanning

Manually trigger Olympix.ai security scanning:
1

Navigate to Actions

Click on the “Actions” tab in your GitHub repository
2

Select Olympix Scan

In the left sidebar, select “Olympix Scan”
3

Run Workflow

Select the branch and click “Run workflow”
4

Review Results

Wait for the scan to complete and review security alerts

Test Coverage

Generate test coverage reports:
forge coverage
View detailed coverage:
forge coverage --report lcov

Coverage Goals

  • Critical paths: 100% coverage
  • Core contracts: >95% coverage
  • Utility functions: >90% coverage
  • Overall project: >90% coverage

Testing Best Practices

Write Comprehensive Tests

function testDepositForBurn() public {
    // Setup
    uint256 amount = 1000e6;
    
    // Execute
    uint64 nonce = tokenMessenger.depositForBurn(
        amount,
        destinationDomain,
        recipient,
        token
    );
    
    // Assert
    assertEq(nonce, 1);
    assertEq(usdc.balanceOf(address(this)), 0);
}

Test Edge Cases

  • Zero amounts
  • Maximum values
  • Invalid addresses
  • Unauthorized callers
  • Paused state
  • Reentrancy scenarios

Use Fuzz Testing

function testFuzz_depositForBurn(uint256 amount) public {
    vm.assume(amount > 0 && amount <= maxAmount);
    
    tokenMessenger.depositForBurn(
        amount,
        destinationDomain,
        recipient,
        token
    );
    
    // Assertions
}

Mock External Dependencies

function setUp() public {
    // Deploy mocks
    mockAttester = new MockAttester();
    
    // Deploy contracts with mocks
    messageTransmitter = new MessageTransmitter(
        address(mockAttester)
    );
}

Troubleshooting

Tests Fail to Compile

  • Check Solidity version (should be 0.7.6)
  • Verify all dependencies are installed
  • Run git submodule update --init --recursive

Tests Timeout

  • Increase timeout in foundry.toml
  • Check for infinite loops in contracts
  • Verify RPC connection is stable

Coverage Reports Empty

  • Ensure tests are passing first
  • Check that test files are in test/ directory
  • Verify forge coverage is configured correctly

Next Steps

Build docs developers (and LLMs) love