Available when Canton Coin launches on Stargate and the Value Transfer API.Canton Coin on BSC, HyperEVM, and Solana is bridged CC: an OFT that LayerZero Labs deployed and administers. It is minted when native CC is locked on Canton through the LayerZero CC adapter. On HyperCore,
LZCC is a spot token linked to the HyperEVM OFT through the Hyperliquid asset bridge. The Global Synchronizer Foundation, Digital Asset, and the Canton Network did not deploy bridged CC and do not administer its contracts. See Canton Coin Across Chains.Prerequisites
- A participant node that hosts your party. Run your own validator node, or host your party on another operator’s node. A validator needs a Super Validator sponsor, an egress IP on the Super Validators’ allowlist, and traffic to submit transactions. See Validators, Super Validators, and the Global Synchronizer.
- A Value Transfer API key. Contact the LayerZero team for a key, and say that you need Canton Coin routes. Send it in the
x-api-keyheader on every call, including/v1/register-canton-party, as in the quickstart. - Access to the LayerZero Canton packages. The DAR packages are private. To get access, contact the LayerZero team with the GitHub handles of the people who will download them.
- The packages vetted on every node that hosts your party. If your party is hosted on more than one participant node, every co-host must upload and vet the same packages. See LayerZero Packages.
- Funded parties. Create and fund your Canton parties before you start. A sending party needs CC for the amount plus the protocol fee from
/v1/quotes. A receiving party needs CC for the registration fee before it can receive any CC. - A registered party for inbound transfers. Register each party that receives CC from another chain, on Canton, before the first inbound send. See Register a Receiving Party.
- Split holdings. The amount and the fee must come from different holdings, so the sending party needs at least two unlocked Amulet holdings. Their total must cover the amount plus the quoted fee, with some margin: the build re-quotes the fee. The API picks one or more holdings for the fee so that the holdings left over cover the amount. Send from an external party, because the Splice wallet merges the holdings of the parties it manages (see Holdings). To create an external party, see Canton’s external signing guide. The party’s key signs every send. Build and submit immediately after you read the holdings.
- Your own signing flow for Canton, and for Solana if you send from Solana. Solana sends need a signer for Solana v1 transactions. See Solana Wallets.
Address Formats
Always pass the full Canton party ID. The API converts it to the 32-byte receiver value for the LayerZero message.
This guide covers Canton mainnet only. It does not cover a testnet route, so test with a small amount on mainnet.
Endpoint Sequence
Get the Canton chain key (canton) from GET /v1/chains, and the CC token addresses from GET /v1/tokens. Use these values in /v1/quotes and /v1/register-canton-party.
1
Get a quote
Call
POST /v1/quotes as on any route. Use Canton party IDs as Canton addresses. Before you quote a route into Canton, check the recipient with POST /v1/register-canton-party (no holdings). /v1/quotes does not check the recipient. On a route into Canton from BSC, HyperEVM, or Solana, /v1/build-user-steps returns the CantonPartyNotRegistered error (HTTP 422; see Errors) if the recipient is not registered. It returns the CantonNamespaceTaken error (HTTP 409) if the recipient’s fingerprint is registered to a different party. A quote from or into Canton has no userSteps. The build step returns them. Quote amounts use base units, as on any route. A transfer carries at most 6 decimal places of CC (shared decimals), so a smaller remainder is not sent.2
Register the receiving party (once)
If the recipient is not registered, it registers once per token, on Canton, before the inbound send.
POST /v1/register-canton-party prepares the registration transaction, and the recipient’s own Canton wallet signs it. See Register a Receiving Party. After the registration transaction commits, request the quote again. Skip this step if the party is already registered.3
Build the transaction
Call
POST /v1/build-user-steps with the quoteId. For a Canton source, include the sender’s holdings in data.holdings. The API does not look up holdings for you. Read them from your node. For a Canton source, the response has one TRANSACTION step with chainType: "CANTON".4
Sign and submit
Sign and submit every user step from
/v1/build-user-steps on the source chain, in order. An ERC-20 source returns an approve step and a send step. For a Canton source, see Submit on Canton.5
Track the transfer
For every source, including Canton, poll
GET /v1/status/{quoteId}?txHash=<hash>. For Canton, pass the update ID that your node or wallet returns. The API maps it to the LayerZero transaction that LayerZero Scan indexes, and links it in explorerUrl. explorerUrl is empty until the API has matched the update ID. Searching Scan for your wallet’s update ID finds nothing. To track the message in code, query the LayerZero Scan API with the transaction hash in explorerUrl. For a Canton source, that transaction can hold several messages: select the one whose sender is your party and whose amount matches. Read the warning below before you act on SUCCEEDED.Acceptance, Refunds, and Rejected Sends
- Inbound CC can wait for acceptance. Unless the receiving party has a CC transfer preapproval, the CC arrives as a transfer instruction that the receiver must accept within 24 hours.
/v1/statusdoes not track acceptance. Tell your users to turn on a preapproval (One-step Transfers in Loop) or to accept the instruction. - Fee change and refunds can arrive the same way. On a send from Canton, unused fee and refunds can also arrive as transfer instructions.
- A send from Canton that VER rejects is not refunded automatically. After VER processes the request, the
lzownerparty rejects it on the ledger (see Protocol Overview). The CC that you sent stays with the LayerZero CC adapter until the refund is settled. Contact the LayerZero team with the party ID, the update ID, and thequoteId. The LayerZero request fee is not refunded.
Build Request for a Canton Source
- Pass only unlocked Amulet holdings owned by the sending party. The API drops holdings with another owner or instrument, but it cannot see locks. A locked holding that you pass can be selected, and the transaction then fails on submit.
- Set
instrumentIdto the structuredfee.instrumentIdthatPOST /v1/register-canton-partyreturns, and pass it through unchanged. Do not derive it from the token address. That call returnsfeeonly for an unregistered party. For a registered party, use the instrument ID that your node reports on the Amulet holding. - Set
amountto the holding’s current amount as a decimal string in CC, as your node reports it, for example"12.5", with at most 10 decimal places. Do not use base units. - Pass at most 200 holdings. More returns HTTP 400
Invalid request. - A send uses at most 100 holdings across the amount and the fee. If you have many small holdings, merge them: send your CC to yourself from an external party, which consolidates the inputs into one holding plus change.
Register a Receiving Party
Registration maps your party’s fingerprint to your full party ID in the CC adapter’s registry. The party signs it with its own wallet or key, in a Canton transaction separate from any send. Register once per party per token. For parties that share a namespace, see the warning under Prerequisites.-
Check the status and the fee. Call
POST /v1/register-canton-partywithpartyIdandtoken, withoutholdings.{"status": "registered", "partyId": "<partyId>"}means no action is needed.{"status": "unregistered", "fee": {...}}gives the fee in CC. If the fee is zero, this response already includes thetransaction. Go to step 3.
-
Get the registration transaction. Call the endpoint again with
holdingsthat cover the fee. The response includes atransactionto sign. - Sign and submit the transaction as the party, as in Submit on Canton.
Submit on Canton
The Canton transaction is a CIP-0103prepareExecute request. In a build step, it is transaction.encoded. In a registration response, it is transaction. It has one command (OApp_LzSend for a send, SetPartyId for a registration), actAs, readAs, and the disclosedContracts that the command needs.
- Internal party (your node holds the key): submit the command with its disclosed contracts through your node’s Ledger API.
- External party (you hold the key): use Canton’s interactive submission. Prepare the transaction with the command and its
disclosedContracts, sign the returned hash with the party key, then execute it. Take the update ID from the completion for yourcommandId./v1/statusneeds it.
commandId. Set your own unique commandId when you submit, and keep the same commandId if you resubmit the same send. The request also has no synchronizerId. It is optional: set it to the Global Synchronizer ID, or leave it unset and your node picks a synchronizer that it is connected to. Do not change the command or its package ID.
You do not need your own idempotency or deduplication checks on Canton. The transaction spends specific holdings, so only one submission of it can commit. Track each send with /v1/status and LayerZero Scan, as in Endpoint Sequence. While a send is pending, do not build a replacement from other holdings.
Sign and submit within a few minutes of the build. The transaction carries a timestamp that the API sets when it builds the transaction. The LayerZero contracts reject it once ledger time is more than 10 minutes past that timestamp. If submission fails with a timestamp-in-the-future error, wait a few seconds and resubmit the same transaction. Contract IDs read at build time can also go stale. If submission fails with a stale or archived contract, request a new quote, read your holdings again, and build again. Calling /v1/build-user-steps again with the old quoteId returns the same transaction. A build that failed is not stored, so you can retry a failed build with the same quoteId.
One Send per Transaction
Each quote gives one command. Submit it as its own Canton transaction. Do not merge commands from several builds into one transaction.- The API picks holdings the same way each time and does not reserve them. Two builds from the same holdings list pick the same holdings, so the second send fails.
- Transfer tracking expects one LayerZero send per Canton transaction.
No Native Drop into Canton
Do not setoptions.dstNativeDropAmount on a route into Canton. Leave it at the default of 0. The fee for a native drop is charged, but the drop is not delivered on Canton.
Deposit Directly to HyperCore
HyperCore is a destination of the Value Transfer API. You can deposit CC to HyperCore in one transaction from Canton, BSC, Solana, or HyperEVM. CallPOST /v1/quotes as on any route, with these destination fields:
An address is activated by its first incoming transfer on HyperCore, which costs 1 USDC. If the address is not activated, the API returns no route. Activate the address first.
From Canton, BSC, or Solana, the API builds an OFT send to the LayerZero Hyperliquid Composer on HyperEVM, with the compose message and compose options. The executor delivers the CC to the composer on HyperEVM, and the composer moves it to the receiver on HyperCore. From HyperEVM, the API builds a transfer to the Hyperliquid asset bridge. Call
/v1/build-user-steps and sign the steps as on any other route.
To leave HyperCore, hold at least 0.001 HYPE on HyperCore for gas, and spot-send LZCC to the asset bridge 0x20000000000000000000000000000000000004E7, or quote HyperCore to HyperEVM with the same sender and receiver address. The CC appears at the same address on HyperEVM. Then bridge from HyperEVM.
Errors
Error responses carrycode and message, and most also carry data. Match on the HTTP status and message. For HTTP 400 Invalid request, read data.validationErrors. The names in the first column are labels for this page only. The API does not send them.
Submission errors come from your node, not the API. For a stale or archived contract, quote, read your holdings, and build again. For a package that is not vetted, vet the full package set on every hosting node. For insufficient traffic, top up your validator’s traffic.
For delivery problems after submission, see Canton Coin Troubleshooting.