Integration Workflows¶
Overview¶
The workflows below are grouped into two integration stages.
MVP for Canton Coin contains the minimum viable product (MVP) workflows for integrating Canton Coin (CC) into the exchange. It comes with the limitation that both the exchange and the customers need to set up a
TransferPreapproval
to enable 1-step transfers of CC.MVP for all Canton Network Tokens contains the additional workflows required to support all CN tokens. They are the workflows to onboard a new token and the workflows to support multi-step transfers for both deposits and withdrawals. Multi-step transfers are a part of the Canton Network Token Standard to support tokens where the receiver is given a choice to reject an incoming transfer as well as to support additional asynchronous checks on transfers by the token admin (e.g. KYC/AML checks).
Further extensions of these two MVPs to address Day-2 requirements are discussed in Integration Extensions.
Important
The current descriptions of the workflows do not yet call out the wallet SDK functions implementing their individual steps; and may thus appear overly detailed and complex. They are meant to give a first overview until the references to the specific SDK functions have been added.
MVP for Canton Coin¶
Note
The diagrams in the sections below adapt the diagram from the Information Flows section to the case for Canton Coin (CC). The adaptations are:
The role of the
adminParty
is taken over by thedsoParty
, which is the token admin for CC. ThedsoParty
is a decentralized party that is hosted on the validator nodes run by SV operators. A confirmation threshold of 2/3 is used to achieve Byzantine fault-tolerance for its transaction validation.The role of the Registry API Server is taken over by the Canton Coin Scan services that every SV operator runs. They serve the Registry API for CC. See Reading from Canton Coin Scan for more information about how to reliably read from multiple Canton Coin Scan instances.
1-Step Deposit Workflow¶

Assumptions:
The Exchange has set up a CC
TransferPreapproval
for theirtreasuryParty
as explained in Setup the treasury party.The Exchange has associated deposit account “abc123” with Customer in the Canton Integration DB.
Example flow:
Customer uses Exchange UI to retrieve
treasuryParty
and deposit account-id “abc123” to use for the depositCustomer uses Customer Wallet to initiate a token standard transfer of 100 CC to
treasuryParty
with metadata keysplice.lfdecentralizedtrust.org/reason
set to “abc123”.Customer Wallet selects CC
Holding
UTXOs to fund the transfer and queries Canton Coin Scan to retrieve registry-specificTransferFactory
and extra transfer context. The returned data includes theTransferPreapproval
for thetreasuryParty
.Customer wallet submits the command to exercise the
TransferFactory_Transfer
choice together with the extra transfer context. The resulting transaction archives the funding CCHolding
UTXOs and creates a CCHolding
UTXO with contract-idcoid234
owned by thetreasuryParty
and another CCHolding
UTXO for the change owned by the Customer.The resulting transaction gets committed across the Customer, Exchange, and SV validator nodes. It is assigned an update-id
upd567
and a record timet1
by the Global Synchronizer. It is assigned offsetoff1
by the Exchange Validator Node.
Tx History Ingestion observes
upd567
att1
with offsetoff1
and updates the Canton Integration DB as follows.Tx History Ingestion parses
upd567
using the token standard tx history parser from the Wallet SDK to determine:The deposit amount of 100 CC.
The deposit account “abc123” from the
splice.lfdecentralizedtrust.org/reason
metadata value.The new
Holding
UTXOcoid234
owned by thetreasuryParty
Tx History ingestion writes the following in a single, atomic transaction to the Canton Integration DB
The latest ingested update-id
upd567
its record timet1
and offsetoff1
.The new CC
Holding
UTXOcoid234
for the 100 CC that was received.The credit of 100 CC on the Customer’s account at the exchange.
Customer observes the successful deposit in their Exchange UI, whose data is retrieved from the Canton Integration DB via the Exchange Internal Systems.
1-Step Withdrawal Workflow¶

Assumptions:
Customer set up a CC
TransferPreapproval
for theircustomerParty
.
Example flow:
Customer requests withdrawal of 100 CC to
customerParty
using the Exchange UI.Exchange Internal Systems process that request and update the Canton Integration DB to store:
The deduction of 100 CC from the Customer’s trading account.
The pending withdrawal with id
wid123
of 100 CC tocustomerParty
.The CC
Holding
UTXOscoids
to use to fund the transfer tocustomerParty
forwid123
. See UTXO Selection and Management for more information.The target record time
trecTgt
on the Global Synchronizer until which the transaction for the CC transfer must be committed. Thecoids
are considered to be reserved for funding the transfer for withdrawalwid123
untiltrecTgt
has passed.
Withdrawal Automation observes the pending withdrawal
wid123
and commits the corresponding CC transfer as follows.Withdrawal Automation queries Canton Coin Scan to retrieve the
TransferFactory
for CC and extra transfer context.Withdrawal automation checks that transfer is indeed a 1-step transfer by checking that
transfer_kind
="direct"
in the response from Canton Coin Scan. If that is not the case, then it marks the withdrawal as failed in the Canton Integration DB and stops processing.Withdrawal Automation prepares, signs, and submits the command to exercise the
TransferFactory_Transfer
choice with the exclusive upper-bound for the record time of the commit set totrecTgt
. It also sets the value for keysplice.lfdecentralizedtrust.org/reason
in theTransfer
metadata towid123
.The resulting transaction archives the CC
Holding
UTXOscoids
used to fund the transfer and creates one CCHolding
UTXO with contract-idcoid345
owned by thecustomerParty
and another one with contract-idcoid789
owned bytreasuryParty
representing the change returned to the Exchange. The resulting transaction gets committed across the Customer, Exchange, and SV validator nodes. It is assigned an update-idupd567
and a record timet1
<trecTgt
by the Global Synchronizer. It is assignedoff1
by the Exchange Validator Node. It is assignedoff2
by the Customer Validator Node.
Tx History Ingestion observes
upd567
att1
with offsetoff1
and updates the Canton Integration DB as follows.Tx History Ingestion parses
upd567
using the token standard tx history parser from the Wallet SDK to determine:The withdrawal-id
wid123
from thesplice.lfdecentralizedtrust.org/reason
metadata value.The new
Holding
UTXOcoid789
owned by thetreasuryParty
Tx History ingestion writes the following in a single, atomic transaction to the Canton Integration DB
The latest ingested update-id
upd567
, its record timet1
and offsetoff1
.The successful completion of withdrawal
wid123
by the transaction with update-idupd567
at record timet1
.The archival of the CC
Holding
UTXOscoids
.The new CC
Holding
UTXOcoid789
for the change returned after funding the CC transfer.
Customer Wallet observes
upd567
att1
with offsetoff2
on the Customer Validator Node, parses it using the token standard tx history parser and updates its UI as follows:Its tx history shows the receipt of 100 CC from
exchangeParty
with “Reason”wid123
that was committed as updateupd567
att1
.Its holding listing shows the new CC
Holding
with contract idcoid345
.
Customer observes the completion of the withdrawal at
t1
in the Exchange UI and the receipt of the expected funds in their Customer Wallet.
UTXO Selection and Management¶
Executing a withdrawal requires selecting Holding
UTXOs to fund the withdrawal,
as described for example in 1-Step Withdrawal Workflow. You likely already have a UTXO management strategy in place for your existing UTXO-chain integrations. Here some considerations to take into account when adapting your strategy to work with Canton:
Canton Coin charges a small holding fee of about $1 per year for each
Holding
UTXO to allow archiving dust coins once their holding fee surpasses their value.Canton Coin limits the number of UTXOs for a single transfer to 100
Holding
UTXOs to avoid large transactions that are expensive to process.Canton Coin transactions also merge all input
Holding
UTXOs and return the change to the sender as a singleHolding
UTXO to allow batching the merging ofHolding
UTXOs with transfers.Other tokens are likely to follow similar strategies for the same rationale.
At the time of writing (2025-08-29), the Canton Network Token Standard recommends to use self-transfers (i.e.,
sender
=receiver
) to be used to mergeHolding
UTXOs into twoHolding
UTXOs: one for the transferredamount
and another one for the change. It does not (yet) support requesting multipleHolding
UTXOs to be created for the change.
We therefore recommend the following approach:
Limit the number of input UTXOs to less than 100 UTXOs per transfer. Thus staying with the Canton Coin limits and keeping transaction size small, which also helps you to reduce your traffic spend when having to retry transaction execution.
Consider using a UTXO selection strategy for withdrawals that favors smaller UTXOs so that they get merged automatically as part of executing transfers.
Consider keeping a pool of k large amount UTXOs to be able to execute up to k withdrawals at the same time. Run a periodic background job to manage this pool using self-transfers.
From an implementation perspective, these self-transfers are a special kind of withdrawal. We thus recommend to implement them using the same code path as withdrawals: start with writing the self-transfer request into the Canton Integration DB and have the Withdrawal Automation execute it.
MVP for all Canton Network Tokens¶
The MVP for supporting all Canton Network tokens builds on the MVP for Canton Coin. The key changes required are:
Change Tx History Ingestion to also ingest the
TransferInstruction
UTXOs, which are used by the Canton Network Token Standard to represent in-progress transfers (see docs, code).Adjust the Exchange UI to show the status of in-progress transfers.
Adjust the user funds tracking done as part of Tx History Ingestion to credit funds back to the user if they reject a withdrawal transfer. Consider deducting a fee for the failed withdrawal.
Implement the Multi-Step Deposit Automation service to auto-accept incoming transfers that are pending receiver acceptance. Ensure that the deposit address is known before accepting the transfer.
Add support for configuring the URL of a token admin’s Registry API Server and to deploy their .dar files as described in Canton Network Token Onboarding.
The sections below provide worked examples for the resulting multi-step deposit and withdrawal workflows. All examples assume that:
There is a token admin called Acme who issues a token called AcmeToken on the Canton Network and operates their own Admin Validator Node and their own Registry API Server.
The Exchange and Customer have onboarded AcmeToken as per Canton Network Token Onboarding.
Multi-Step Deposit Workflow¶

Example flow: deposit offer and acceptance¶
The flow uses essentially the same initial four steps as the 1-Step Deposit Workflow above. We list them in full for completeness.
Customer uses Exchange UI to retrieve
treasuryParty
and deposit account-id “abc123” to use for the deposit.Customer uses Customer Wallet to initiate a token standard transfer of 100 AcmeToken to
treasuryParty
with metadata keysplice.lfdecentralizedtrust.org/reason
set to “abc123”.Customer Wallet selects AcmeToken
Holding
UTXOs to fund the transfer and queries Acme’s Registry API Server to retrieve registry-specificTransferFactory
and extra transfer context. The URL for this server was configured in the Customer Wallet as part of Canton Network Token Onboarding.Customer wallet submits the command to exercise the
TransferFactory_Transfer
choice together with the extra transfer context. The resulting transaction archives the funding AcmeTokenHolding
UTXOs and creates a locked 100 AcmeTokenHolding
UTXO with contract-idcoid234
owned by thecustomerParty
and another AcmeTokenHolding
UTXO for the change owned by the Customer. The transaction also creates aTransferInstruction
UTXO with contract-idcoid567
, which represents the transfer offer to the Exchange.The resulting transaction gets committed across the Customer, Exchange, and Acme validator nodes. It is assigned an update-id
upd567
and a record timet1
by the Global Synchronizer. It is assigned offsetoff1
by the Exchange Validator Node.
Tx History Ingestion observes
upd567
att1
with offsetoff1
and updates the Canton Integration DB as follows.Tx History Ingestion parses
upd567
using the token standard tx history parser from the Wallet SDK to determine:The deposit amount of 100 AcmeToken.
The deposit account “abc123” from the
splice.lfdecentralizedtrust.org/reason
metadata value.The
TransferInstruction
UTXOcoid567
representing the transfer offer for the deposit.
Tx History ingestion writes the following in a single, atomic transaction to the Canton Integration DB
The latest ingested update-id
upd567
its record timet1
and offsetoff1
.The
TransferInstruction
UTXOcoid567
representing the transfer offer fromcustomerParty
for a deposit of 100 AcmeToken in account “abc123”.
Customer Wallet ingests update
upd567
and Customer observes the pending transfer offer for the deposit in the Customer Wallet. Customer also sees the 100 AcmeTokenHolding
UTXOcoid234
locked to the deposit.
This is where the main difference to the 1-Step Deposit Workflow starts. The Multi-Step Deposit Automation service will now auto-accept the transfer offer.
The Multi-Step Deposit Automation regularly queries for pending transfer offers for known deposit accounts. It thus observes the pending transfer offer
coid567
and accepts it as follows.Multi-Step Deposit Automation retrieves the URL for Acme’s Registry API Server from the Canton Integration DB.
Multi-Step Deposit Automation queries Acme’s Registry API Server to retrieve the extra context to exercise the
TransferInstruction_Accept
choice oncoid567
.Multi-Step Deposit Automation prepares, signs, and submits the command to exercise the
TransferInstruction_Accept
choice oncoid567
.The resulting transaction gets committed across the Customer, Exchange, and Acme validator nodes. It is assigned an update-id
upd789
and a record timet2
the Global Synchronizer. It is assignedoff3
by the Exchange Validator Node. The resulting transaction has the following effects:It archives the
TransferInstruction
UTXOcoid567
.It archives the locked 100 AcmeToken
Holding
UTXOcoid234
owned by thecustomerParty
.It creates a 100 AcmeToken
Holding
UTXOcoid999
owned by thetreasuryParty
.
At this point the workflow again proceeds the same way as the 1-Step Deposit Workflow.
Tx History Ingestion observes
upd789
att2
with offsetoff3
and updates the Canton Integration DB as follows.Tx History Ingestion parses
upd789
using the token standard tx history parser from the Wallet SDK to determine:The deposit amount of 100 AcmeToken.
The deposit account “abc123” from the
splice.lfdecentralizedtrust.org/reason
metadata value.
Tx History ingestion writes the following in a single, atomic transaction to the Canton Integration DB
The latest ingested update-id
upd789
, its record timet2
and offsetoff3
.The new AcmeToken
Holding
UTXOcoid999
for the 100 AcmeToken that was received.The credit of 100 AcmeToken on the Customer’s account at the exchange.
Customer Wallet observes
upd789
att2
on the Customer Validator Node, parses it using the token standard tx history parser and updates its UI as follows:Its tx history shows the successful transfer of 100 AcmeToken to
exchangeParty
with “Reason”wid123
that was committed as updateupd789
att2
.
Customer observes the successful deposit in their Exchange UI, whose data is retrieved from the Canton Integration DB via the Exchange Internal Systems.
Example: handling deposits with unknown deposit accounts¶
To minimize traffic cost, we recommend not acting on deposits with unknown deposit accounts. The sender can use their wallet to withdraw the offer.
Ingesting deposit offers with unknown deposit accounts is still valuable to allow the exchange’s support team to handle customer inquiries about these transfers.
Multi-Step Withdrawal Workflow¶

Example flow: withdrawal offer and acceptance¶
The flow uses essentially the same initial six steps as the 1-Step Withdrawal Workflow above. We list them in full for completeness.
Customer requests withdrawal of 100 AcmeToken to
customerParty
using the Exchange UI.Exchange Internal Systems process that request and update the Canton Integration DB to store:
The deduction of 100 AcmeToken from the Customer’s trading account.
The pending withdrawal with id
wid123
of 100 AcmeToken tocustomerParty
.The AcmeToken
Holding
UTXOscoids
to use to fund the transfer tocustomerParty
forwid123
. See UTXO Selection and Management for more information.The target record time
trecTgt
on the Global Synchronizer until which the transaction for the AcmeToken transfer must be committed using thecoids
UTXOs for fundingwid123
. Thecoids
are considered to be reserved to funding this transfer untiltrecTgt
has passed.
Withdrawal Automation observes the pending withdrawal
wid123
and commits the corresponding AcmeToken transfer as follows.Withdrawal Automation retrieves the URL for Acme’s Registry API Server from the Canton Integration DB.
Withdrawal Automation queries Acme’s Registry API Server to retrieve the
TransferFactory
for AcmeToken and extra transfer context.Withdrawal Automation prepares, signs, and submits the command to exercise the
TransferFactory_Transfer
choice with the exclusive upper-bound for the record time of the commit set totrecTgt
. It also sets the value for keysplice.lfdecentralizedtrust.org/reason
in theTransfer
metadata towid123
; and it sets the upper bound for the customer to accept the transfer far enough in the future (e.g. 30 days).The resulting transaction gets committed across the Customer, Exchange, and Acme validator nodes. It is assigned an update-id
upd567
and a record timet1
<trecTgt
by the Global Synchronizer. It is assignedoff1
by the Exchange Validator Node. It is assignedoff2
by the Customer Validator Node. The resulting transaction has the following effects:It archives the AcmeToken
Holding
UTXOscoids
used to fund the transfer.It creates an AcmeToken
Holding
UTXO with contract-idcoid789
owned bytreasuryParty
representing the change returned to the Exchange.It creates one locked AcmeToken
Holding
UTXO with amount 100 and contract-idcoid345
owned by thetreasuryParty
.It creates a
TransferInstruction
UTXO with contract-idcoid567
representing the transfer offer. ThisTransferInstruction
includes a copy of theTransfer
specification and its metadata.
Tx History Ingestion observes
upd567
att1
with offsetoff1
and updates the Canton Integration DB as follows.Tx History Ingestion parses
upd567
using the token standard tx history parser from the Wallet SDK to determine:The withdrawal-id
wid123
from thesplice.lfdecentralizedtrust.org/reason
metadata value.The new locked AcmeToken
Holding
UTXOcoid345
owned by thetreasuryParty
.The new AcmeToken
Holding
UTXOcoid789
owned by thetreasuryParty
The
TransferInstruction
UTXOcoid567
representing the transfer offer for the withdrawal.
Tx History ingestion writes the following in a single, atomic transaction to the Canton Integration DB:
The latest ingested update-id
upd567
, its record timet1
and offsetoff1
.The successful transfer offer for withdrawal
wid123
by the transaction with update-idupd567
at record timet1
.The
Holding
UTXOcoid345
locked to the withdrawal.The
TransferInstruction
UTXOcoid567
representing the transfer offer.The archival of the AcmeToken
Holding
UTXOscoids
.The new AcmeToken
Holding
UTXOcoid789
for the change returned after funding the AcmeToken transfer.
Exchange UI displays that withdrawal
wid123
is pending transfer offer acceptance by the Customer.Customer Wallet observes update with update-id
upd567
att1
with offsetoff2
on the Customer Validator Node.It parses the transaction using the token standard transaction history parser and updates its UI so that its transaction history shows the offer for a transfer of 100 AcmeToken from
exchangeParty
with “Reason”wid123
that was committed as updateupd567
att1
.
This is where the main difference to the 1-Step Withdrawal Workflow starts. The customer has a choice whether to accept or reject the transfer offer. Here they choose to accept it.
Customer uses their Customer Wallet to accept the offer using the
TransferInstruction_Accept
choice.The resulting transaction is committed across Exchange, Acme, and Customer validator nodes and assigned update-id
upd789
and record timet2
. The transaction has the following effects:It archives the locked
Holding
UTXOcoid345
.It archives the
TransferInstruction
UTXOcoid567
.It creates a 100 AcmeToken
Holding
UTXOcoid999
owned by thecustomerParty
.
Tx History Ingestion observes update
upd789
att2
and offsetoff3
assigned by the Exchange Validator Node.It parses the update using the token standard parser to extract the withdrawal-id
wid123
from thesplice.lfdecentralizedtrust.org/reason
metadata value.Tx History Ingestion writes the following in a single, atomic transaction to the Canton Integration DB
The latest ingested update-id
upd789
, its record timet2
and offsetoff3
.The successful completion of the withdrawal
wid123
by the transaction with update-idupd789
at record timet2
.The archival of the locked AcmeToken
Holding
UTXOcoid345
.
Customer Wallet observes
upd789
att2
and updates its display to reflect its effects.Customer observes the completion of the withdrawal at
t2
in Exchange UI and confirms the receipt of funds in their Customer Wallet.
Example flow: customer rejects transfer offer¶
The Customer might decide to reject the offer in Step 7 in the example above. The corresponding transaction will
archive the locked
Holding
UTXOcoid345
,archive the
TransferInstruction
UTXOcoid567
, andcreate a new 100 AcmeToken
Holding
UTXOcoid999
owned by thetreasuryParty
.
Steps 8 - 10 are largely the same as for the successful acceptance with the difference that Tx History Ingestion will see this transaction and update the Canton Integration DB to such that
withdrawal
wid123
is marked as failed because the customer rejected the offer, andthe customer account is credited back the 100 AcmeToken, potentially minus a fee for the failed withdrawal.
And the user will ultimately see in both the Exchange UI and the Customer Wallet that the transfer was offered, but rejected by them.
Note
In most cases a TransferInstruction
will be completed in a single extra step:
the receiver either accepts or rejects the transfer, or the sender withdraws it.
Each of these steps will manifest as one of the choices on the TransferInstruction
interface
(code)
and its TransferInstructionResult.output
value clearly tells whether the instruction
completed with a successful transfer, failed, or is still pending an action by one of the stakeholders.
Canton Network Token Onboarding¶
You likely have exchange internal requirements and considerations for onboarding a token. In the following, we document the additional considerations that are specific to Canton.
At a high-level, the Canton-specific steps to onboarding a token are:
Upload the token admin’s .dar files to your validator node.
Store the mapping from the token admin’s
adminParty
id to the admin’s Registry API Server URL in your Canton Integration DB (or another suitable place).In case the token is permissioned, follow the token admin’s instructions to have your exchange’s
treasuryParty
added to the token’s allowlist.
Make sure that you only upload .dar files from trusted token admins to avoid unwanted changes to the behavior of your existing contracts on-ledger.
Many token admin’s run a test instance of their token on TestNet. Consider using these test instances as part of your testing strategy.
For example, Canton Coin also exist on TestNet and DevNet
with different dsoParty
ids.
You can retrieve the dsoParty
id for each network using the
CC Scan API
served from the SV nodes of that network:
Use /v0/dso to query the
dsoParty
for the network you are connected to.Use /v0/splice-instance-names to query the network name (DevNet, TestNet, or MainNet).