# Programmable Token Transfers: Canton as Destination
Source: https://docs.chain.link/ccip/canton/tutorials/destination/programmable-token-transfers
Last Updated: 2026-07-06

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

> **CAUTION**
>
> Addresses shown may change due to upgrades since Canton contracts are immutable. Confirm party IDs and contract addresses with [Chainlink CCIP](https://chain.link/ccip-contact).

This tutorial demonstrates how to send a **programmable token transfer (PTT)** from Ethereum Sepolia to Canton — TEST tokens plus arbitrary data — and execute it on Canton using the [`ccip-starter-kit-canton`](https://github.com/smartcontractkit/ccip-starter-kit-canton).

> **NOTE: Prerequisites**
>
> Complete the [Canton as Destination prerequisites](/ccip/canton/tutorials/destination/prerequisites) and review [Token Transfers (Canton as Destination)](/ccip/canton/tutorials/destination/token-transfers). You need Sepolia TEST tokens (`npm run faucet:evm-test`) and Canton ledger access.
>
> These steps use **Canton testnet** and **Ethereum Sepolia** only.

## Introduction

A programmable token transfer delivers both tokens and a data payload to the destination. On Canton, execution:

1. Resolves or creates a `CCIPReceiver` for the message finality.
2. Processes `TokenReceiveTicket` and mints LINK via the token pool.
3. Delivers the attached data to your receiver logic through `ccipReceive` on Canton.

## What You Will Build

In this tutorial, you will:

- Send `1` TEST plus a UTF-8 data string from Sepolia with `any2canton:data-and-token`.
- Execute on Canton with `any2canton:manual-exec`.
- Verify LINK balance and message execution.

## Understanding Programmable Token Transfers (any2canton)

| Aspect               | Token-only                               | Programmable token transfer            |
| :------------------- | :--------------------------------------- | :------------------------------------- |
| **Send script**      | `any2canton:token`                       | `any2canton:data-and-token`            |
| **Data**             | Empty                                    | `--dataString` payload                 |
| **Canton execution** | LINK mint + accept `TransferInstruction` | LINK mint + data delivered to receiver |

The execution path fetches proofs, Global CCIP EDS disclosures, and token pool operator EDS inputs — see the [Canton as Destination flow](/ccip/canton/concepts/overview#public-chain--canton).

## Running the Tutorial

### Prerequisites Check

1. Complete [prerequisites](/ccip/canton/tutorials/destination/prerequisites).
2. Mint TEST on Sepolia:

   ```bash filename="Terminal"
   npm run faucet:evm-test
   ```

## Step 1: Send data + TEST from Sepolia

```bash filename="Terminal"
npm run any2canton:data-and-token -- --dataString "Hello" --amount 1
```

Pay CCIP fee in LINK:

```bash filename="Terminal"
npm run any2canton:data-and-token -- \
  --dataString "Hello" \
  --amount 1 \
  --feeToken link
```

> **NOTE: Finality not customizable for LINK token transfers**
>
> The starter kit uses the TEST ↔ LINK token pool, which only supports default (`finalized`) source finality. A custom `--finality` on token sends is only supported if your token pool supports it — since this starter kit uses LINK, do **not** pass `--finality` to `any2canton:data-and-token`. Wait for Sepolia finality before running `any2canton:manual-exec`.

### Expected send output

```text
📧🪙 Sending data + 1 TEST from Sepolia → Canton: "Hello"
   Receiver party: yourParty::1220…
   LINK is minted on Canton only after manual execution.
🆔 CCIP Message ID: 0x…

⚙️  Execute on Canton once the message is finalized on Sepolia:
   npm run any2canton:manual-exec -- 0x<messageId>
```

## Step 2: Execute on Canton

After finality and Committee Verifier proofs are on the indexer:

```bash filename="Terminal"
npm run any2canton:manual-exec -- <sepoliaTxHash | messageId>
```

Pass either the **Sepolia source transaction hash** (`📜 Source transaction`) or the **CCIP Message ID** (`🆔 CCIP Message ID`, `0x…`) — `any2canton:manual-exec` accepts both.

Optional custom receiver hint:

```bash filename="Terminal"
npm run any2canton:manual-exec -- <sepoliaTxHash | messageId> --receiver 'yourParty::1220…'
```

## Verification

1. **CCIP Explorer**: Confirm SUCCESS for the transfer.
2. **LINK balance**: `npm run check-balance -- --chain canton --token link`
3. **Canton Lighthouse**: Inspect the execution transaction for token pool and receiver activity.

> **CAUTION: Educational Example Disclaimer**
>
> Please note, this page contains community examples only — these are not Chainlink products or services and are not
> supported or maintained by Chainlink. This code represents an example of using a Chainlink product or service, and is
> intended for demonstration and educational purposes only. It is provided "AS IS" and "AS AVAILABLE" without warranties
> of any kind, may not have been audited, and may omit checks or error handling. Each party intending to use this
> example code does so entirely at their own risk and must perform its own audits, security and code review, key
> management, and testing before any production deployment and ensure the operation and performance of such code matches
> expectations. Neither Chainlink Labs nor the Chainlink Foundation deploys, operates, monitors, maintains or endorses
> any deployment of this code. Note that this is not a Chainlink product, feature or service, and there are no
> commitments made with respect to the code, including compatibility with future Chainlink releases. You should not rely
> on this code without first conducting your own technical, engineering, and security review. This code is also outside
> the scope of any Chainlink bug bounty programs. Neither Chainlink Labs, the Chainlink Foundation, nor Chainlink node
> operators are responsible for outcomes due to errors in this example or how it is deployed or operated, or liable for
> any resulting claims or damages. Use of the Chainlink Network is subject to the Chainlink Foundation [Terms of
> Service](https://chain.link/terms), which provides important information and disclosures. By using this code, you
> acknowledge and agree to these terms.