Registry Issuer Guide (Canton)

Audience: Engineers who understand Canton and want to issue a token through Digital Asset's Registry utility and connect it to Chainlink CCIP.

Outcome: A live Registry instrument on Canton, initial token supply on-ledger, a registrar-owned CCIP BurnMint token pool, and registration in the Token Admin Registry (TAR) so Chainlink can bridge the token once lane configuration is complete.

1. Overview

Two on-ledger systems connect at a single instrument identity:

LayerPurposeAnalog
DA RegistryWho may issue this token and how much exists on CantonTransfer agent + securities registry
Chainlink CCIPHow this Canton token enters and exits cross-chain lanesBridge + router + token pool

Flow: Provider onboards Registrar → Registrar creates instrument and mints → Registrar deploys CCIP BurnMint pool → TAR links instrument to pool → Chainlink ops validates cross-chain lanes.

Critical identity rule

CCIP identifies your token with an InstrumentId:

InstrumentId = { admin: <registrar party>, id: "<your instrument string>" }

The admin field must be your registrar party. Wrong party → TAR and pool will not recognize your token.

This guide covers issuer/registrar steps only. Chainlink operations must have deployed CCIP core contracts, configured lanes, and provided contract references before you begin. Cross-chain send/receive (CCIPSender.Send, CCIPReceiver.Execute) are validated separately once your token is registered.

2. Parties and roles

PartyOrganizationRole in this guide
DA OperatorDigital AssetAccepts Provider onboarding; Operator Backend for context/disclosure
ProviderToken program owner (you)Onboards registrars; credential requirements
RegistrarTransfer agent / treasuryCreates instrument, mints, owns CCIP pool, TAR admin
IssuerMint requester (optional)Requests mint when credentials apply
HolderInvestor / end userHolds balances — no Registry service onboarding required
CCIP ownerChainlinkOwns TAR, OnRamp, OffRamp, shared CCIP infrastructure

Recommended: three parties under your org — Provider, Registrar, Holder — plus Chainlink's CCIP owner on the participant.

Registry onboarding: DA Registry onboarding guide.

3. Prerequisites

ValueUsed for
Ledger JSON API URLAll ledger submissions
OAuth client (scoped to your parties)JWT — do not use shared admin clients
can_act_as rightsProvider, Registrar, optional Issuer/Holder
CCIP owner party IDTAR ProposeAdministrator
TokenAdminRegistry contract IDTAR exercises
RMNRemote / FeeQuoter addressesPool dependencies
Remote chain selectorPool RemoteChainConfig
Remote pool / token addresses (hex)Pool lane config
DA Operator party IDRegistry onboarding

3.2 Values you choose

ValueGuidance
Instrument IDShort uppercase, e.g. ACME-USD
Pool instance IDe.g. acme-usd-ccip-pool
Rate limiter instance IDsInbound default, inbound custom, outbound
Initial mint amounte.g. 1000000.0

3.3 Environment requirements

Devnet, testnet, and mainnet are provisioned by operators. Issuers do not upload DAR packages.

ResponsibilityProviderWhat you get
Registry utility DARs (≥ 0.12.5)Participant / DA operatorRegistry template code on-ledger
CCIP DAR packagesChainlink opsTAR, pools, OnRamp, OffRamp templates
Registry choice contextDA Operator BackendextraArgs.context, disclosedContracts
CCIP choice contextCCIP EDSDisclosures for TAR, pool, router exercises

DARs vs disclosures: DARs must exist before contracts can be created (infrastructure). Disclosures are fetched at request time for contracts your party is not a stakeholder on — include them in JSON API submissions.

3.4 Optional tooling — canton-registry-kit

Chainlink provides a CLI automating many Registry and TAR steps on devnet. Every automated step maps to an on-ledger exercise documented below.

Example registry-kit.toml:

network = "devnet-cv1"

[ledger]
json_api_url = "https://<your-participant>/api/json"
grpc_ledger_api_url = "<your-participant>:443"
admin_api_url = "<your-participant>:443"
user_id = "your-ledger-user-id"
synchronizer_id = "global-domain::1220..."

[ledger.auth]
type = "authorizationCode"
auth_url = "https://your-idp/oauth2/default"
client_id = "your-oauth-client-id"

[parties]
operator = "operator-party::1220..."
provider = "provider-party::1220..."
registrar = "registrar-party::1220..."

[ccip]
token_admin_registry_cid = "00..."
ccip_party = "ccip-owner-party::1220..."
burn_mint_pool_instance_id = "your-pool-instance-id"

[operator_backend]
base_url = "https://api.utilities.digitalasset-dev.com/api/utilities"

Global flags: canton-registry-kit --config registry-kit.toml [--state registry-kit.state.json]

4. End-to-end workflow

PhaseStepsActor
A — Registry onboarding1–6Provider (+ DA Operator)
B — Instrument and mint7–9Registrar
C — CCIP pool deploy10–13Registrar (pool owner)
D — TAR registration14–17CCIP owner + Registrar
E — Verification18Registrar

Hand off to Chainlink ops for lane testing after Phase E.

5. Phase A — Registry onboarding

Request/accept workflow on-ledger. UI walkthrough: DA issuance onboarding tutorial.

Step 1 — Verify environment

canton-registry-kit onboarding check-packages

If packages missing, contact participant operator — do not upload DARs unless you operate the validator.

Step 2 — Request Provider service

FieldValue
TemplateProviderServiceRequest
Create asProvider
Fieldsoperator = DA Operator, provider = your Provider

CLI: canton-registry-kit onboarding request-provider-service

Step 3 — Wait for Provider acceptance

DA Operator exercises ProviderServiceRequest_Accept → creates ProviderService.

CLI: canton-registry-kit onboarding wait-provider-service --timeout 15m

Step 4 — Create Provider configuration

Choice: ProviderService_CreateProviderConfiguration (Provider). Use empty registrarRequirements / holderRequirements for simplest path.

Step 5 — Request Registrar service

Template: RegistrarServiceRequest (Provider). Set createAllocationFactory = true, createTransferRule = true.

The AllocationFactory implements Splice BurnMintFactory — CCIP uses it for burn/mint on Registry holdings.

Step 6 — Accept Registrar service

Choice: ProviderService_AcceptRegistrarServiceRequest → creates RegistrarService, AllocationFactory, TransferRule.

CLI (Steps 4–6): canton-registry-kit onboarding onboard-registrar

Record: RegistrarService, AllocationFactory, TransferRule CIDs.

Inspect: canton-registry-kit onboarding discover-registry-factories

6. Phase B — Create instrument and mint

Registry 0.12.5+ uses AllocationFactory two-step mint (RequestMintAccept).

Step 7 — Create instrument

Choice: RegistrarService_CreateInstrumentConfiguration (Registrar). instrumentId e.g. ACME-USD.

Your CCIP InstrumentId: { admin: <registrar>, id: "ACME-USD" }

CLI: canton-registry-kit issuer create-instrument ACME-USD

Step 8 — Request mint

Choice: AllocationFactory_RequestMint. Fetch Operator Backend context first:

POST {operator_backend}/v0/registry/mint/v0/request
Body: { "holder": "<holder>", "instrumentId": { "admin": "<registrar>", "id": "ACME-USD" } }

Include choiceContextData and disclosedContracts in ledger submission.

CLI: canton-registry-kit issuer mint --amount 1000000.0 --holder <holder-party>

Step 9 — Accept mint

Choice: MintRequest_Accept with Operator Backend context:

POST {operator_backend}/v0/registry/mint/v0/request/{mintRequestCid}/choice-contexts/accept

CLI: canton-registry-kit issuer accept-mint

Verify: canton-registry-kit issuer query-supply

7. Phase C — Deploy CCIP token pool

Performed via Ledger API — no CLI for pool deployment today. Deploy rate limiters first, then pool.

Steps 10–12 — Rate limiters

Deploy three RateLimiter contracts:

  • Inbound, mode = DefaultFinality
  • Inbound, mode = CustomFinality
  • Outbound

Step 13 — Deploy BurnMintTokenPool

FieldValue
instanceIde.g. acme-usd-ccip-pool
poolOwnerRegistrar
ccipOwnerFrom Chainlink ops
instrumentId{ admin: registrar, id: "ACME-USD" }
decimals10
deps.*TAR, RMNRemote, FeeQuoter bindings
remoteChainConfigs[selector]Remote pool/token addresses from ops

Record pool address {poolInstanceId}@{registrarParty} and all rate limiter CIDs.

Full field reference: BurnMint Token Pool Deployment.

8. Phase D — Register in Token Admin Registry

Steps 14–16 — Propose, accept, set pool

StepChoiceAct as
14ProposeAdministratorCCIP owner
15AcceptAdminRoleRegistrar
16SetPoolRegistrar

Steps 15–16 require TAR disclosed to registrar (CCIP EDS or CLI).

CLI (14–16): canton-registry-kit operator link-token-to-pool

Step 17 — SetBurnMintFactory (required)

Mandatory for Registry tokens — links TAR to your AllocationFactory from Step 6.

FieldValue
ChoiceSetBurnMintFactory on TokenAdminRegistry
Act asRegistrar
burnMintFactoryAllocationFactory CID from Step 6

Without this, cross-chain transfers fail at execution. CCIP EDS assembles Registry-specific pool context at runtime.

Reference: DA burn-mint how-to.

9. Phase E — Verification

canton-registry-kit operator validate
CheckHow
Instrument identityInstrumentId.admin = registrar; id matches Registry config
HoldingsActive Holding(s); supply matches mint
TAR mappingTokenConfig references your pool and registrar as admin
Factory linkTokenConfig.burnMintFactory = AllocationFactory CID
Pool activeBurnMintTokenPool at {poolInstanceId}@{registrarParty}

10. CLI command reference

All commands: --config registry-kit.toml [--state registry-kit.state.json]

Onboarding

CommandDescription
onboarding check-packagesVerify Registry DARs (read-only)
onboarding request-provider-serviceSubmit ProviderServiceRequest
onboarding wait-provider-servicePoll until DA accepts
onboarding onboard-registrarProviderConfiguration + RegistrarService + AllocationFactory
onboarding discover-registry-factoriesList Registry contracts for registrar

Issuer

CommandDescription
issuer create-instrument <ID>Create InstrumentConfiguration
issuer mint --amount <N> [--holder <party>]RequestMint via Operator Backend
issuer accept-mintAcceptMint
issuer query-supplySum Holding balances

Operator (CCIP linking)

CommandDescription
operator link-token-to-poolProposeAdministrator → AcceptAdminRole → SetPool
operator validateRead-only TAR and instrument checks

CLI gaps (Ledger API only)

  • Deploy RateLimiter contracts
  • Deploy BurnMintTokenPool
  • SetBurnMintFactory

11. Troubleshooting

SymptomCauseResolution
Mint credential errorMissing issuer credentialsIssue per DA credential docs or use empty requirements
Bridge fails after SetPoolSetBurnMintFactory not calledExercise Step 17 with AllocationFactory CID
Pool doesn't recognize tokenWrong InstrumentId.adminMust be registrar, not Provider or CCIP owner
Registry choice failsMissing Operator Backend contextCall Operator Backend before submission
Missing utility packagesParticipant not provisionedContact operator
TAR exercise failsTAR not disclosedUse CCIP EDS or link-token-to-pool
403 from Ledger APIVPN / wrong OAuth clientScoped client with can_act_as

12. Glossary

TermDefinition
InstrumentIdCCIP token ID: { admin: party, id: string }
HoldingRegistry balance record for an instrument
AllocationFactoryRegistry factory implementing Splice BurnMintFactory
TARTokenAdminRegistry — maps instrument → pool + admin
EDSChainlink Execution Disclosure Service
Disclosed contractContract blob in submission for non-stakeholder exercise

13. Further reading

TopicLink
Registry introductionRegistry user guide
Token Standard integrationToken Standard
Issuance tutorialIssuance onboarding
Utility DAR versionsDAR versions

What's next

Get the latest Chainlink content straight to your inbox.