# LockRelease Token Pool Deployment (Canton)
Source: https://docs.chain.link/ccip/tutorials/canton/cross-chain-tokens/lock-release-token-pool
Last Updated: 2026-07-06

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

Deploy a **LockRelease** token pool on Canton, fund pool-owner liquidity, register on the Token Admin Registry (TAR), and enable a cross-chain lane. Use the [`ccip-starter-kit-canton`](https://github.com/smartcontractkit/ccip-starter-kit-canton) for pool deployment and TAR registration, or submit Ledger API commands directly.

This guide assumes you have a token instrument live on Canton with supply minted on-ledger, supporting the CIP-56 `TransferFactory` interface and transfer pre-approvals.

**LockRelease** is for **fixed total supply** tokens where cross-chain transfers are backed by locked liquidity — not mint/burn. On send, tokens lock to the pool owner; on receive, the pool releases from its holdings.

**Scope:** Deploy pool, fund liquidity, register on TAR, enable a lane. Excludes [EDS setup](/ccip/concepts/canton/explicit-disclosure) and end-to-end transfer tests.

> **NOTE: Testnet only**
>
> Starter kit `cct:*` scripts target **Canton testnet** only.

> **CAUTION**
>
> Addresses shown may change. Confirm party IDs and contract addresses with Chainlink CCIP.

## Prerequisites

- Instrument with known `InstrumentId = { admin, id }` supporting `TransferFactory` and pre-approvals.
- Token liquidity held by the pool owner party for expected release volume.
- CCIP DAR packages from [`contracts/dars/v2_0_0`](https://github.com/smartcontractkit/chainlink-canton/tree/main/contracts/dars/v2_0_0).
- CCIP contract references from Chainlink ops.
- **Starter kit setup** (if using `cct:*` scripts) — complete [Canton as Source prerequisites](/ccip/tutorials/canton/source/prerequisites) and the [CCT overview](/ccip/tutorials/canton/cross-chain-tokens#starter-kit-cct-scripts).

> **CAUTION: Pool owner trust**
>
> CCIP fully trusts the pool owner. Strongly recommend pool owner equals instrument admin, decentralized across nodes.

## Deployment overview

| Step | Action                           | Starter kit               | Manual                              |
| :--- | :------------------------------- | :------------------------ | :---------------------------------- |
| 1    | Deploy `LockReleaseTokenPool`    | `cct:deploy-lock-release` | Ledger API `CreateCommand`          |
| 2    | Fund holdings + set pre-approval | —                         | Ledger API choices                  |
| 3    | Register on TAR                  | `cct:set-token`           | TAR choices via Ledger API          |
| 4    | Enable lane                      | —                         | Rate limiters + `ApplyChainUpdates` |
| 5    | Go live                          | —                         | EDS + verification                  |

## Step 1 — Deploy the LockRelease Token Pool

Create one [`LockReleaseTokenPool`](https://github.com/smartcontractkit/chainlink-canton/blob/main/contracts/ccip/pools/lock-release-token-pool/daml/CCIP/LockReleaseTokenPool.daml). Signatory: `poolOwner`.

### Transfer-fee fields

When setting `tokenTransferFeeConfigs` (map keyed by destination chain selector):

| Field               | Meaning                                                 |
| :------------------ | :------------------------------------------------------ |
| `isEnabled`         | Must be `true` to apply the config                      |
| `feeUSDCents`       | Flat fee in USD cents (non-negative)                    |
| `destGasOverhead`   | Gas for destination execution (> 0 when set via choice) |
| `destBytesOverhead` | Data-availability bytes overhead (≥ 32)                 |
| `feeBps`            | Proportional fee in basis points (\< 10000)             |

### CCIP hosted addresses

| Field                     | Testnet                                                                                                    | Mainnet                                                                                                    |
| :------------------------ | :--------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- |
| Token Admin Registry      | `tokenadminregistry-lzrnd@ccipOwner::1220e382f4e57b0815e6be737006e381e6b7de448e06bd033ece6df498017879f551` | `tokenadminregistry-ckswd@ccipOwner::122012714685760dc1927c4cfe119ce2126c48756154e95c06f5c181da05a5519093` |
| RMNRemote                 | `rmn_remote-nzvtd@rmnOwner::1220e382f4e57b0815e6be737006e381e6b7de448e06bd033ece6df498017879f551`          | `rmn_remote-mnprd@rmnOwner::122012714685760dc1927c4cfe119ce2126c48756154e95c06f5c181da05a5519093`          |
| FeeQuoter                 | `feequoter-scxln@ccipOwner::1220e382f4e57b0815e6be737006e381e6b7de448e06bd033ece6df498017879f551`          | `feequoter-fpxih@ccipOwner::122012714685760dc1927c4cfe119ce2126c48756154e95c06f5c181da05a5519093`          |
| CCIP owner party          | `ccipOwner::1220e382f4e57b0815e6be737006e381e6b7de448e06bd033ece6df498017879f551`                          | `ccipOwner::122012714685760dc1927c4cfe119ce2126c48756154e95c06f5c181da05a5519093`                          |
| Global EDS                | `https://eds.testnet.ccip.chain.link`                                                                      | `https://eds.ccip.chain.link`                                                                              |
| Indexer                   | `https://indexer-1.testnet.ccip.chain.link`                                                                | `https://indexer-1.ccip.chain.link` (backup: `indexer-2`)                                                  |
| Canton chain selector     | `9268731218649498074`                                                                                      | `2308837218439511688`                                                                                      |
| Default CommitteeVerifier | `committeeverifier-tqkny@ccvOwner::1220e382f4e57b0815e6be737006e381e6b7de448e06bd033ece6df498017879f551`   | `committeeverifier-mnprd@ccvOwner::122096accf0a84fc7d80d5fce5ea3135317a03eb22e62e0d8cdd7548865f984f11ff`   |

## Step 2 — Fund the pool and configure pre-approval

LockRelease liquidity comes from the **pool owner's token holdings**. Top up those holdings to match expected outbound volume — there is no separate on-pool deposit step. When a receiver executes an inbound transfer on Canton, tokens move from the pool owner's holdings to the recipient.

> **NOTE: Manual step**
>
> The starter kit does not automate funding or pre-approval. Complete this step via the Ledger API before registering on TAR.

### Set pool receive preapproval

Record the token's transfer preapproval in `poolReceiveContext` so inbound transfers to the pool owner succeed atomically on send:

```shell
curl --request POST \
  --url https://<your-participant>/api/json/v2/commands/submit-and-wait-for-transaction-tree \
  --header "authorization: Bearer $JWT" \
  --header 'content-type: application/json' \
  --data '{
  "commands": [
    {
      "ExerciseCommand": {
        "templateId": "#ccip-lock-release-token-pool:CCIP.LockReleaseTokenPool:LockReleaseTokenPool",
        "contractId": "<POOL_CONTRACT_ID>",
        "choice": "AddPoolReceiveContextContractValue",
        "choiceArgument": {
          "contextKey": "transfer-preapproval",
          "referredContract": "<PREAPPROVAL_CONTRACT_ID>"
        }
      }
    }
  ],
  "commandId": "set-pool-receive-preapproval",
  "actAs": ["<POOL_OWNER_PARTY>"]
}'
```

| Field              | Value                                                        |
| :----------------- | :----------------------------------------------------------- |
| `contextKey`       | Key the TransferFactory expects, e.g. `transfer-preapproval` |
| `referredContract` | ContractId of the pool owner's transfer preapproval          |

Related choices: `AddPoolReceiveContextNonContractValue`, `RemovePoolReceiveContextValue`, `ClearPoolReceiveContext`.

## Step 3 — Register on the Token Admin Registry

TAR maps each instrument to a single token pool. Registration: **propose → accept → set pool**.

## Step 4 — Enable a lane

Lane enablement is **not** automated by the starter kit.

### 1. Deploy three rate limiters

Each lane requires [`RateLimiter`](https://github.com/smartcontractkit/chainlink-canton/blob/main/contracts/ccip/core/daml/CCIP/RateLimiter.daml) contracts (for testing, deploy disabled with zero capacity/rate):

- **Inbound (default finality)**
- **Inbound (custom finality)**
- **Outbound**

Created by `poolOwner` with matching `poolInstanceId`, `poolOwner`, and `remoteChainSelector`.

### 2. Apply the chain update

Call [`ApplyChainUpdates`](https://github.com/smartcontractkit/chainlink-canton/blob/main/contracts/ccip/pools/lock-release-token-pool/daml/CCIP/LockReleaseTokenPool.daml) on the pool:

| ChainUpdate field                            | Guidance                                                                   |
| :------------------------------------------- | :------------------------------------------------------------------------- |
| `remoteChainSelector`                        | Destination chain selector — see [CCIP Directory](/ccip/directory/testnet) |
| `remotePools`                                | Remote token pool address(es)                                              |
| `remoteTokenAddress`                         | Remote token address                                                       |
| `inboundCCVs` / `outboundCCVs`               | Default CommitteeVerifier (testnet address above) unless custom            |
| `finalityConfig`                             | `WaitForFinality` for default finalized source tx                          |
| `inboundRateLimiter`                         | Inbound default limiter CID                                                |
| `inboundCustomBlockConfirmationsRateLimiter` | Inbound custom limiter CID                                                 |
| `outboundRateLimiter`                        | Outbound limiter CID                                                       |

Once applied, the on-ledger lane is complete.

## Step 5 — Go live

### Verification checklist

1. TAR maps instrument to pool with your party as admin.
2. Pool at `{instanceId}@{poolOwner}` with matching `InstrumentId`.
3. Pool owner holds sufficient liquidity; receive preapproval set in `poolReceiveContext`.
4. Lane rate limiters in place.

### Stand up EDS

The [reference EDS](https://github.com/smartcontractkit/chainlink-canton/blob/main/eds/eds.Dockerfile) supports LockRelease, including holdings and TransferFactory context for pre-approvals.

### Test transactions

See [CCIP on Canton — Overview](/ccip/concepts/canton/overview) and [CCIP Explorer](/ccip/tools-resources/ccip-explorer).

> **CAUTION: Educational Example Disclaimer**
>
> This page includes an educational example to use a Chainlink system, product, or service and is provided to
> demonstrate how to interact with Chainlink's systems, products, and services to integrate them into your own. This
> template is provided "AS IS" and "AS AVAILABLE" without warranties of any kind, it has not been audited, and it may be
> missing key checks or error handling to make the usage of the system, product or service more clear. Do not use the
> code in this example in a production environment without completing your own audits and application of best practices.
> Neither Chainlink Labs, the Chainlink Foundation, nor Chainlink node operators are responsible for unintended outputs
> that are generated due to errors in code.