Contract Addresses and example

CCTP and anyCall contract addresses:

Testnet:

Ethereum (Goerli)

MessageTransmitter: 0x26413e8157cd32011e726065a5462e97dd4d03d9

TokenMessenger: 0xd0c3da58f55358142b8d3e06c1c30c5c6114efe8

anyCall: 0x965f84D915a9eFa2dD81b653e3AE736555d945f4

Avalanche (Fuji)

MessageTransmitter: 0xa9fb1b3009dcb79e2fe346c16a604b8fa8ae0a79

TokenMessenger: 0xeb08f243e5d3fcff26a9e38ae5520a669f4019d0

anyCall: 0x461d52769884ca6235b685ef2040f47d30c94eb5

Mainnet

Ethereum

MessageTransmitter: 0x0a992d191DEeC32aFe36203Ad87D7d289a738F81

TokenMessenger: 0xBd3fa81B58Ba92a82136038B25aDec7066af3155

anyCall: 0x8efd012977DD5C97E959b9e48c04eE5fcd604374

Avalanche

MessageTransmitter: 0x8186359af5f57fbb40c6b14a588d2a59c0c29880

TokenMessenger: 0x6B25532e1060CE10cc3B0A99e5683b91BFDe6982

anyCall: 0x8efd012977DD5C97E959b9e48c04eE5fcd604374

Use of each contracts:

  1. TokenMessenger: Used on the source chain to burn USDC

  2. anyCall: Used on source chain to send instructions for destination contract to execute

  3. MessageTransmitter: Used to receive USDC on the destination chain

Example:

This example contract allows users to bridge USDC via CCTP and anyCall to the destination chain with one tx. You can fork the contract and edit to your needs.

Source Chain Tx: https://testnet.snowtrace.io/tx/0x411bfb0292aaa028ca6668cf8d739133272aebde57881ac69d3513916eb6c036

Destination Tx: https://goerli.etherscan.io/tx/0x7ac77c73d557d96e7c1014beafc95122455567b4afbcbb4070385aa443225dbd

Mainnet Example:

https://scan.multichain.org/#/tx?params=0xd5435680d0e6d7f2e656a9410cc53f2cdfeba340699079dc84e35d5dba10ee58

You can edit logic in function callout and function anyExecute to suit your use case.

Steps to integrate anyCall + CCTP

  1. Call depositForBurnWithCaller to burn the $USDC

depositForBurnWithCaller

Same as depositForBurn, but with an additional parameter, destinationCaller. This parameter specifies which address has permission to call receiveMessage on the destination domain for this message.

Parameters

Field
Type
Description

amount

uint256

Amount of tokens to deposit and burn.

destinationDomain

uint32

Destination domain identifier.

mintRecipient

bytes32

Address of mint recipient on destination domain.

burnToken

address

Address of contract to burn deposited tokens, on local domain.

destinationCaller

bytes32

Caller on the destination domain, as bytes32.

CircleBridge(usdcBridge).depositForBurnWithCaller(
            _amount,
            _destinationDomain,
            toBytes32(_mintRecipient),
            _burnToken,
            toBytes32(_clientPeer)
        );

  1. Pass additional contract data you want the destination chain to receive with anyCall. Read the guide below on the basics of anyCall. The syntax is the same except you have to pass string "usdc" as the _extdata.

bytes memory _calldata = abi.encode(_amount, _mintRecipient);
bytes memory _extdata = "usdc";
IAnycallProxy(callProxy).anyCall{value: msg.value}(
                _clientPeer,
                _calldata,
                _toChainId,
                AnycallFlags.FLAG_NONE,
                _extdata)
  1. The call data of anyCall and data for CCTP would be passed to anyExecute. You can then extract the attestation to get the funds with receiveMessage.

receiveMessage

Messages with a given nonce can only be broadcast successfully once for a pair of domains. The message body of a valid message is passed to the specified recipient for further processing.

Parameters

Field
Type
Description

message

bytes memory

Message bytes.

attestation

bytes calldata

signed attestation of message.

function anyExecute(bytes calldata data)
        external
        override
        onlyExecutor
        returns (bool success, bytes memory result)
    {
        (address _sender, uint256 _fromChainId, ) = _getAndCheckContext();
        (
            bytes memory _calldata,
            string memory _swapid,
            bytes memory _message,
            bytes memory _attestation
        ) = abi.decode(data, (bytes, string, bytes, bytes));

        (uint256 _amount, address _mintRecipient) = abi.decode(
            _calldata,
            (uint256, address)
        );

        require(!completedCallin[_swapid], "completed");
        completedCallin[_swapid] = true;

        // use the message transmitter by circle to claim usdc
        USDCMessageTransmitter(usdcMessageTransmitter).receiveMessage(
            _message,
            _attestation
        );
```

Last updated