# How to Use Chainlink CCIP

### The minimal CCIP architecture <a href="#the-minimal-ccip-architecture" id="the-minimal-ccip-architecture"></a>

To recap, with Chainlink CCIP, one can:

* Transfer (supported) tokens
* Send any kind of data
* Send both tokens and data

CCIP receiver can be:

* EOA
* Any smart contract that implements `CCIPReceiver.sol`

<figure><img src="https://3336775262-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FVxFPzCGStHLGRVz3QBdQ%2Fuploads%2FJXa4senAKWCvKwdZMbQL%2F6.avif?alt=media&#x26;token=779707d3-e734-4b64-b82b-0fd799931ede" alt=""><figcaption><p>Basic CCIP Architecture</p></figcaption></figure>

**Note**: If you send a message and token(s) to EOA, only tokens will arrive.

For now, you can consider CCIP as a "black-box" component and be aware of the Router contract only. We will explain the Chainlink CCIP architecture in the following chapters.

### Getting started <a href="#getting-started" id="getting-started"></a>

You can use Chainlink CCIP with any blockchain development framework. For this Masterclass, we prepared the steps for Hardhat, Foundry, and Remix IDE.

Let's create a new project

{% tabs %}
{% tab title="Hardhat" %}
Make sure you have [Node.js](https://nodejs.org/en/download) and [NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) installed. To check, run the following command:

```sh
node -v
```

```sh
npm -v
```

Create a new folder and name it `ccip-masterclass`

```sh
mkdir ccip-masterclass
```

Navigate to it

```sh
cd ccip-masterclass
```

Create a hew Hardhat project by running:

```shell
npx hardhat@2.14.1 init
```

And then select either "Create a JavaScript project" or "Create a TypeScript project".
{% endtab %}

{% tab title="Foundry" %}
Make sure you have [Foundry](https://book.getfoundry.sh/getting-started/installation) installed. To check, run the following command:

```sh
forge --version
```

Create a new folder and name it `ccip-masterclass`

```sh
mkdir ccip-masterclass
```

Navigate to it

```sh
cd ccip-masterclass
```

Create a hew Foundry project by running:

```sh
forge init
```

{% endtab %}

{% tab title="Remix" %}
Navigate to <https://remix.ethereum.org/> and click the "Create new Workspace" button.
{% endtab %}
{% endtabs %}

Alternatively, you can clone:

* [CCIP Starter Kit (Hardhat version)](https://github.com/smartcontractkit/ccip-starter-kit-hardhat)
* [CCIP Starter Kit (Foundry version)](https://github.com/smartcontractkit/ccip-starter-kit-foundry)

### The @chainlink/contracts-ccip NPM package <a href="#the-chainlink-contracts-ccip-npm-package" id="the-chainlink-contracts-ccip-npm-package"></a>

To use Chainlink CCIP, you need to interact with Chainlink CCIP-specific contracts from the [@chainlink/contracts-ccip](https://www.npmjs.com/package/@chainlink/contracts-ccip) NPM package.

{% embed url="<https://www.npmjs.com/package/@chainlink/contracts-ccip>" %}

To install it, follow steps specific to the development environment you will use for this Masterclass.

{% tabs %}
{% tab title="Hardhat" %}

```bash
npm i @chainlink/contracts-ccip --save-dev
```

{% endtab %}

{% tab title="Foundry" %}
**Option 1)**

We cannot use git submodules to install `@chainlink/contracts-ccip` because the content of this package is not available as a separate GitHub repo. This essentially means that we cannot run a `forge install` command.\
\
Here's the workaround:

Add the following line to the `.gitignore` file

```gitignore
# Node modules
node_modules/
```

Then run the following command in your Terminal:

```sh
npm i @chainlink/contracts-ccip --save-dev
```

Finally, add the following lines to the `foundry.toml` file:

```toml
libs = ['node_modules', 'lib']
remappings = [
    '@chainlink/contracts-ccip/=node_modules/@chainlink/contracts-ccip'
]
```

**Option 2) \[October 2023 UPDATE]**

You can run&#x20;

```sh
forge install smartcontractkit/ccip@ccip-develop
```

And after that set remappings in your `foundry.toml` or `remappings.txt` files to&#x20;

```toml
# foundry.toml
remappings = [
    '@chainlink/contracts-ccip/=lib/ccip/contracts/'
]
```

{% endtab %}

{% tab title="Remix" %}
Create a new Solidity file, and paste the following content. It is an empty contract that just imports one of the contracts from the `@chainlink/contracts-ccip` package.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";

contract Empty {}
```

Compile it. If compiled successfully and new `.deps/npm/@chainlink/contracts-ccip` folders are generated, that means we imported the `@chainlink/contracts-ccip` package into the Remix IDE Workspace.

<figure><img src="https://3336775262-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FVxFPzCGStHLGRVz3QBdQ%2Fuploads%2FR0PkVayDowOppsIE0L8j%2FHow%20to_Day%201_Remix.png?alt=media&#x26;token=00cca5d2-6656-4291-8dd5-79e7e8df6be8" alt=""><figcaption><p>Remix IDE compile</p></figcaption></figure>
{% endtab %}
{% endtabs %}

## Basic interface

Although, as being said, CCIP sender and receiver can be EOA and smart contract, and all combinations are possible, we are going to cover the most complex use-case where both CCIP sender and receiver are smart contracts on different blockchains.

#### Source blockchain <a href="#source-blockchain" id="source-blockchain"></a>

To send CCIP Messages, the smart contract on the source blockchain must call the `ccipSend()` function, which is defined the `IRouterClient.sol` interface.

```solidity
// SOURCE BLOCKCHAIN 

interface IRouterClient {
    /// @notice Request a CCIP message to be sent to the destination chain
    /// @param destinationChainSelector The destination chain selector
    /// @param message The cross-chain CCIP message including data and/or tokens
    /// @return messageId The message ID
    function ccipSend(
        uint64 destinationChainSelector,
        Client.EVM2AnyMessage calldata message
    ) external payable returns(bytes32 messageId);
}
```

The CCIP Message which is being sent is a type of `EVM2AnyMessage` Solidity struct from the `Client` library.

```solidity
// SOURCE BLOCKCHAIN

library Client {
    struct EVM2AnyMessage {
        bytes receiver; // abi.encode(receiver address) for dest EVM chains
        bytes data; // data payload
        EVMTokenAmount[] tokenAmounts; // token transfers
        address feeToken; // fee token address; address(0) means you are sending msg.value
        bytes extraArgs; // populate this with _argsToBytes(EVMExtraArgsV1)
    }
    
    struct EVMTokenAmount {
        address token; // token address on local blockchain
        uint256 amount;
    }
    
    struct EVMExtraArgsV1 {
        uint256 gasLimit;
        bool strict;
    }
}
```

Let's now understand what each property of the `EVM2AnyMessage` struct we are sending represents and how to use it.

**receiver**

Receiver address. It can be a smart contract or an EOA. Use `abi.encode(receiver)` to encode the address to the `bytes` Solidity data-type.

**data**

Payload sent within the CCIP message. This is that "any type of data" one can send as a CCIP Message we are referring to from the start. It can be anything from simple text like "Hello, world!" to Solidity structs or function selectors.

**tokenAmounts**

Tokens and their amounts in the source chain representation. Here we are specifying which tokens (out of supported ones) we are sending and how much of it. This is the array of a `EVMTokenAmount` struct, which consists of two properties only:

* `token` - Address of a token we are sending on the local (source) blockchain
* `amount` The amount of tokens we are sending. The sender must approve the CCIP router to spend this amount on behalf of the sender, otherwise the call to the `ccipSend` function will revert.

Currently, the maximum number of tokens one can send in a single CCIP send transaction is five.

**feeToken**

Address of feeToken. CCIP supports fee payments in LINK and in alternative assets, which currently include native blockchain gas coins and their ERC20 wrapped versions. For developers, this means you can simply pay on the source chain, and CCIP will take care of execution on the destination chain. Set `address(0)` to pay in native gas coins such as ETH on Ethereum or MATIC on Polygon. Keep in mind that even if you are paying for fees in the native asset, nodes in the Chainlink DON will be rewarded in LINK only.

**extraArgs**

Users fill in the `EVMExtraArgsV1` struct and then encode it to bytes using the `_argsToBytes` function. The struct consists of two properties:

* `gasLimit` - The maximum amount of gas CCIP can consume to execute `ccipReceive()` on the contract located on the destination blockchain. **Unspent gas is not refunded.** This means that if you are sending tokens to EOA, for example, you should put 0 as a `gasLimit` value because EOAs can't implement the `ccipReceive()` (or any other) function. To estimate the accurate gas limit for your destination contract, consider Leveraging Ethereum client RPC by applying `eth_estimateGas` on `receiver.ccipReceive()` function, or use the [Hardhat plugin for gas tests](https://github.com/cgewecke/eth-gas-reporter), or conduct [Foundry gas tests](https://book.getfoundry.sh/forge/gas-tracking).
* `strict` - Used for strict sequencing. **You should set it to `false`**. CCIP will always process messages sent from a specific sender to a specific destination blockchain in the order they were sent. If you set `strict: true` in the `extraArgs` part of the message, and if the `ccipReceive` fails (reverts), it will ***prevent any following messages from the same sender from being processed until the current message is successfully executed***. You should be very careful when using this feature to avoid unintentionally stopping messages from the sender from being processed. The strict sequencing feature is currently experimental, and there is no guarantee of its maintenance or further development in the future.

If `extraArgs` are left empty, a.k.a `extraArgs: ""`, a default of *200\_000* `gasLimit` will be set with no strict sequencing. For production deployments, make sure that `extraArgs` is mutable. This allows you to build it off-chain and pass it in a call to a function or store it in a variable that you can update on demand. This makes `extraArgs` compatible with future CCIP upgrades.

#### Destination blockchain <a href="#destination-blockchain" id="destination-blockchain"></a>

To receive CCIP Messages, the smart contract on the destination blockchain must implement the `IAny2EVMMessageReceiver` interface. The [@chainlink/contracts-ccip](https://www.npmjs.com/package/@chainlink/contracts-ccip) NPM package comes up with the contract which implements it in the right way, called `CCIPReceiver.sol`, but we are going to talk more about it in the next chapter. For now, let's understand which functions from the `IAny2EVMMessageReceiver` interface must be implemented in the general-case scenario.

```solidity
// DESTINATION BLOCKCHAIN

/// @notice Application contracts that intend to receive messages from 
/// the router should implement this interface.
interface IAny2EVMMessageReceiver {
    /// @notice Router calls this to deliver a message
    /// @param message CCIP Message
    /// @dev Note ensure you check that msg.sender is the Router
    function ccipReceive(Client.Any2EVMMessage calldata message) external;
}
```

As you can see, the `ccipReceive()` function from the `IAny2EVMMessageReceiver` interface accepts object of the `Any2EVMMessage` struct from the `Client` library. This struct is the Solidity representation of the received CCIP Message. Please note that this struct, `Any2EVMMessage` is **different** than the one we used to send on the source blockchain - `EVM2AnyMessage`.  They are not the same.

```solidity
// DESTINATION BLOCKCHAIN

library Client {
    struct Any2EVMMessage {
        bytes32 messageId; // MessageId corresponding to ccipSend on source
        uint64 sourceChainSelector; // Source chain selector
        bytes sender; // abi.decode(sender) if coming from an EVM chain
        bytes data; // payload sent in original message
        EVMTokenAmount[] tokenAmounts; // Tokens and their amounts at destination
    }
    
    struct EVMTokenAmount {
        address token; // token address on local blockchain
        uint256 amount;
    }
}
```

Let's now understand what each property of the `Any2EVMMessage` struct we are receiving represents and how to use it.

* `messageId` - CCIP Message Id, generated on the source chain.
* `sourceChainSelector` - Source chain selector.
* `sender` - Sender address. `abi.decode(sender, (address))` if the source chain is an EVM chain.
* `data` - Payload sent within the CCIP message. For example, "Hello, world!"
* `tokenAmounts` - Received tokens and their amounts in their destination chain representation.

To recap, here's the diagram with the minimal architecture needed to send & receive the Chainlink CCIP Message:&#x20;

<figure><img src="https://3336775262-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FVxFPzCGStHLGRVz3QBdQ%2Fuploads%2FOKYYkXFZlr21lrV86CAY%2Fimage.png?alt=media&#x26;token=37f31054-8273-44a3-8976-0d870193d05f" alt=""><figcaption><p>Developer Interfaces</p></figcaption></figure>
