Canton Network
Rocky settles on Canton Network MainNet: spot fills between customer accounts are delivered atomically (DvP) between the parties' wallets, every order event and every fill (house included) is committed to the ledger once per epoch, perpetual fills are anchored on-chain in batches, and deposits, withdrawals and the proof of solvency can all be verified against the ledger. This page introduces Canton's core concepts and Rocky's current role in the network.
1. What is Canton Network
Canton Network is a privacy-first public network for regulated financial assets, designed by Digital Asset and built on the Daml smart-contract language.
Compared to global-shared-ledger chains:
| Dimension | Ethereum / Solana | Canton Network |
|---|---|---|
| Data visibility | Everything public | Each contract is only visible to its stakeholders (privacy by default) |
| State synchronization | Whole-network consensus on a single ledger | Multiple Synchronizers each arbitrate independently; cross-app interactions settle across them |
| Smart contract model | EVM account model | Daml contracts (multi-signatory + explicit stakeholders) |
| Regulatory friendliness | Hard to comply when everything is public | Built-in privacy + auditability — friendly to financial institutions |
Canton fits use cases like:
- Tokenization of regulated assets (equities, bonds, funds, stablecoins)
- B2B on-chain settlement (clearing houses, custodians, market makers)
- Apps that need provable settlement + data isolation (Rocky is one)
2. Core concepts
2.1 Party
The basic identity unit in Canton. A Party can be a person, an institution, an application, a custodian, etc. Each has a unique id:
alice::1220ca15423a1b049bf8e84132360f246057aa18f5e9e36a77db535b75bd287cceff
^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
party hint participant fingerprint suffix
- Party hint — human-readable prefix, chosen by the app or wallet that creates the party
- Suffix — key fingerprint of the Participant node hosting the party; it differs per wallet / validator
Rocky does not allocate parties for users. A user signs in with a Canton wallet party they already control: call POST /v1/wallet/challenge to get a challenge message, sign it with the wallet key, then submit it to POST /v1/wallet/verify. Rocky verifies the signature and binds that party to the trading account. The supported wallet providers are listed by GET /v1/wallet/providers (Rocky Wallet, Console, Loop, Send).
2.2 Contract
A Daml contract is a data structure with an explicit stakeholder list. Each contract must declare:
- Signatory — parties that must agree on creation and archival
- Observer — parties that can read but not modify
- Controller — parties that can exercise a
choice(action)
Below is the DepositIntent template Rocky actually deploys (daml/perp-custody). The user declares a deposit; the exchange exercises Accept to credit it:
template DepositIntent
with
exchange : Party -- observer: Rocky exchange party
user_handle : Party -- signatory: user party
user_id_hex : Text
asset : Text
amount : Decimal
chain_tx_id : Text
created_at : Time
where
signatory user_handle
observer exchange
ensure amount > 0.0
choice Accept : ContractId PlatformAccount
with
platform_account_cid : ContractId PlatformAccount
controller exchange
do
exercise platform_account_cid Credit with
delta = amount
chain_tx_id = chain_tx_id
Daml templates Rocky currently deploys: ExchangeAuthority, PlatformAccount, FeeCollectorAccount, PerpTradeCustody, DepositIntent, WithdrawalReceipt, RockyEpochCommitment. Spot DvP settlement and CC transfers do not use private templates; they go through the public Canton Token Standard interfaces.
Key property: a contract is only visible to its stakeholders. Other parties on the same Synchronizer never see it. This is Canton's "privacy by default".
2.3 Synchronizer
Comparable to a "blockchain" in Ethereum terms, except that multiple Synchronizers coexist. Each Synchronizer:
- Orders and reaches consensus on the state changes of contracts within it
- Is run by a set of Sequencer + Mediator nodes (a single operator or a decentralized group)
- Interoperates with other Synchronizers via the Canton Network Protocol
Rocky connects to the Global Synchronizer on Canton MainNet (global-domain::1220b1431ef2…, operated by the Splice DSO).
2.4 Participant node
A Party is never "on-chain" by itself. It must be hosted by a Participant node, which is what actually talks to the Synchronizer.
Rocky backend (canton-bridge) User wallet (Console / Loop / Send …)
↓ JSON Ledger API v2 ↓
Rocky Validator ←→ Global Synchronizer ←→ Wallet's Validator
↓ ↓
Party: Rocky exchange Party: user
Rocky runs its own Validator (api.validator.rocky.exchange), which hosts the exchange party and its operator / shadow parties. User parties are hosted by the validator behind their wallet, not on Rocky's node; users who pick Rocky Wallet use the Splice wallet that ships with Rocky's validator.
2.5 Validator
A Validator is the standardized participant deployment provided by the Splice project: Participant + wallet app + OAuth integration.
How Rocky's backend talks to its Validator:
- JSON Ledger API v2 to submit Daml commands and subscribe to the update stream
- Validator API to read wallet views such as Holdings / balances
- Auth0 machine-to-machine (M2M) tokens to authenticate backend services; Auth0 is not part of user login — user identity comes from the wallet-signature binding in §2.1
3. Privacy model
Canton enforces privacy at three levels:
- Contract level — the payload is visible only to signatories + observers
- Participant level — a participant only receives contracts that involve parties it hosts (it stores nothing unrelated)
- Synchronizer level — the synchronizer only sees encrypted commitments (for ordering), never contract contents
Using the contracts Rocky actually writes on-chain:
PerpTradeCustody(perp fill batch) — signatory: Rocky exchange — visible only to RockyDepositIntent— signatory: user, observer: Rocky exchange — visible only to the user and RockyWithdrawalReceipt— signatory: Rocky exchange, observer: user — visible only to Rocky and the user- Spot DvP fill — two Token Standard transfers in one atomic Canton transaction — visible only to the two parties of the fill (wallet-to-wallet, or user wallet to Rocky's custody party)
Other users, other validators and the Synchronizer nodes cannot see any of this data, yet the Synchronizer still provides ordering guarantees and double-spend protection for every state change.
4. Rocky's role in Canton
4.1 Party roles
| Party | Config | Responsibility |
|---|---|---|
| Rocky exchange | EXCHANGE_PARTY_ID | Platform party; signatory of PerpTradeCustody, WithdrawalReceipt, PlatformAccount; key held in KMS |
| Rocky operator | EXCHANGE_OPERATOR_PARTY_ID | Operator party in Token Standard transfer / authorization flows |
| Shadow user | SHADOW_USER_PARTY_ID | Rocky-controlled placeholder party for on-chain records that need no user-owned party |
| DSO | DSO_PARTY_ID | Decentralized operator of the Global Synchronizer (Splice DSO), third party |
| User | held by the wallet | The user's own party, bound via /v1/wallet/verify; Rocky never holds its key |
4.2 On-chain vs off-chain data
Not every trading action goes on-chain. Rocky is off-chain matching + on-chain settlement of the key events:
| Data | Where | Notes |
|---|---|---|
| Order book, matching state | rocky-backend (Postgres) | High frequency; not viable on-chain |
| Trading-account balances | rocky-backend ledger.accounts | High-frequency updates |
| Spot fills between customer accounts | Canton, Token Standard DvP | Settled per fill by spot-chain-settler; each fill returns a cantonUpdateId — see On-chain Settlement |
| Event journal: every order, cancel and fill (house included) | Canton, RockyEpochCommitment | One contract per 60 s epoch: Merkle root over the journal plus the epoch's fill records; inclusion proofs at GET /v1/chain/proof — see Epoch Commitments |
| Perp fill batches | Canton, PerpTradeCustody | settlement-batcher flushes every 5 s or every 10 fills, submitted via canton-bridge |
| Deposits / withdrawals | Canton, Token Standard transfers + DepositIntent / WithdrawalReceipt | See CC Deposit Flow |
| Proof of solvency | Daily ledger snapshot + Merkle Sum Tree commitment | See Proof of Solvency |
| User identity (Party) | The participant behind the user's wallet | Reusable across apps |
4.3 What users see on-chain
Where a Rocky user touches Canton:
- Login — sign a challenge with the wallet and bind the party (
/v1/wallet/challenge→/v1/wallet/verify) - Deposit — send a Token Standard transfer from the wallet to Rocky's exchange party; the backend observes it and credits the account
- Spot trading — a fill involving your account settles on-chain as a DvP (the
cantonUpdateIdonGET /api/v3/myTradescan be verified on the ledger), and every order and fill is additionally committed in the next epoch (GET /v1/chain/proof) - Withdrawal — Rocky transfers from the exchange party to the user party and records a
WithdrawalReceipt - Audit — use the proof of solvency to check that your liabilities are included and reserves cover them
5. Environments
| Environment | Canton access | Use |
|---|---|---|
| Production | Canton MainNet Global Synchronizer via Rocky's own validator (api.validator.rocky.exchange) | The live api.rocky.exchange service |
| Local development | Canton sandbox (single participant, offline, CANTON_AUTH_MODE=none) | make canton-up in the backend repo |
Rocky has no DevNet deployment. User party suffixes differ from one another, depending on the validator behind each wallet.
6. Further reading
- Canton Network Whitepaper
- Daml Documentation
- Splice Documentation
- Related pages on this site: CC Deposit Flow, Proof of Solvency, Spot On-chain Settlement