Skip to main content

CC Deposit Flow

CC (Canton Coin) is the native token of the Canton Network Global Synchronizer, issued by the Splice DSO as Amulet contracts. It is not a Rocky-issued token. This page explains how a user deposits CC from their own wallet into a Rocky trading account. The same flow applies to every Token Standard (CIP-56) asset Rocky supports; only the on-chain transfer mechanism differs (see §4).

Concepts used: Canton Party, Holding, Token Standard, canton-bridge. Read Canton Network first if needed.

The assets that can currently be deposited are those with deposit_enabled in GET /v1/assets. In production today: CC, CUSD, CBTC, cETH, USDC.B, USDCx, USX, aCC.


1. Overview​

Rocky runs on Canton MainNet. A deposit is a real on-chain transfer from the user's own wallet party to the Rocky exchange party. Rocky creates no contracts on the user's behalf and never holds the user's key.

User wallet (Rocky Wallet / Console / Loop / Send)
│ 1. POST /v1/deposits/reference → target_party_id + deposit_ref
│ 2. Transfer to target_party_id in the wallet, reason/memo = deposit_ref
▼
Canton Global Synchronizer
│ user Holding −N, exchange Holding +N
▼
canton-bridge consumer (Ledger API update stream)
│ 3. Validate receiver / asset / deposit_ref / sender / amount
│ 4. Exercise PlatformAccount.Credit as the exchange party (KMS-signed)
│ 5. Publish NATS chain.events.deposit
▼
internal-ledger
│ 6. Idempotently credit ledger.spot_balances.free += N
│ 7. deposit_intents status → credited
▼
Frontend polls GET /v1/deposits and balances, shows the deposit as credited

Key point: a transfer without a deposit_ref is never credited automatically (see §6).


2. User's view​

  1. Sign in with a wallet (/v1/wallet/challenge → /v1/wallet/verify) to obtain a session token
  2. On the deposit page pick an asset and amount; Rocky issues a deposit reference (deposit_ref) valid for 1 hour
  3. Following the on-screen instructions, transfer from the wallet to the Rocky exchange party with deposit_ref in the transfer's reason / memo (Rocky Wallet and Send Wallet fill it in automatically)
  4. Once the Synchronizer confirms the transfer, canton-bridge normally observes and credits it within seconds
  5. The deposit record moves to credited and the spot balance increases

Rocky charges no deposit fee. Any traffic / gas cost shown by the wallet or validator is node traffic cost paid on the user side.


3. API​

Every endpoint uses Authorization: Bearer <session_token> (from POST /v1/wallet/verify).

3.1 Create a deposit reference​

POST /v1/deposits/reference

Request fieldRequiredDescription
assetyesAsset symbol or alias, e.g. CC, CUSD
amount_expectednoExpected amount (positive decimal string). When set, the on-chain amount must match exactly
providernoWallet provider; defaults to the session's provider
binding_idnoWallet binding id; defaults to the session's binding

Response:

{
"deposit_id": "1a2b3c4d-…",
"asset": "CC",
"wallet_symbol": "CC",
"target_party_id": "<Rocky exchange party>",
"deposit_ref": "rocky:deposit:1a2b3c4d-…",
"reason_metadata_key": "splice.lfdecentralizedtrust.org/reason",
"expires_at": "2026-09-07T07:30:00Z",
"chain_action_policy": {
"customer_chain_tx_window_hours": 12,
"deposit_ref_required": true
}
}
  • target_party_id is EXCHANGE_PARTY_ID, shared by all assets
  • deposit_ref must be placed verbatim in the transfer metadata under the key given by reason_metadata_key
  • wallet_symbol / wallet_display_name / aliases are the names the asset carries inside wallets, to help the UI guide the user to the right asset
  • The reference is bound to the session party that created it: the on-chain sender must be that party

3.2 Deposit history​

GET /v1/deposits

Returns the current user's most recent 100 deposit intents:

FieldDescription
deposit_id, asset, amount_expected, deposit_refAs created
statuspending (waiting for the transfer) → observed (bridge saw the transfer) → credited; also expired, rejected
chain_tx_id, canton_update_idThe on-chain update once credited; verifiable in Canton Scan or on any participant hosting your party
created_at, expires_at, credited_atUTC timestamps

3.3 Send Wallet only​

POST /v1/deposits/send/transfer-factory

Send Wallet sessions only. The frontend hands the Token Standard TransferFactory choice arguments to Rocky, which assembles them via canton-bridge for Send Wallet to sign and submit. Other wallets perform the transfer inside the wallet and do not use this endpoint.


4. On-chain transfer mechanisms​

AssetMechanismNotes
CCSplice Amulet TransferPreapprovalThe Rocky exchange party registers a CC TransferPreapproval; wallets send CC straight to the exchange party through it. The bridge reads receiver, amount and deposit_ref from TransferPreapproval_Send* events
CUSD, CBTC, cETH, USDC.B, USDCx, USX, aCCToken Standard (CIP-56) TransferFactoryThe transfer is either Direct (lands immediately) or an Offer (creates a TransferInstruction the exchange must accept). Offers addressed to the exchange party whose reason starts with rocky:deposit: are accepted automatically by the bridge, also KMS-signed

The bridge only recognizes instruments registered in the canton-bridge configuration (admin party and instrument id must both match). Same-named tokens with a different instrument (for example the legacy USDCx) are rejected and logged.


5. Funds flow​

Depositing N units of an asset:

LayerChange
On-chain Holdingsuser party −N, exchange party +N
Daml PlatformAccount(asset)+N after Credit; chain_tx_id records the source update
Rocky sub-ledgerledger.spot_balances.free +N; deposit_intents.status = credited

Deposits land in the spot wallet. To use them as perpetual margin, move them with Spot Transfer.


6. Bridge validation and failure handling​

canton-bridge credits a transfer only when all of the following hold:

  1. The receiver is the current Rocky exchange party
  2. The asset instrument is registered
  3. The reason metadata starts with rocky:deposit: and matches a deposit intent in status pending / observed
  4. The intent has not expired (1 hour after creation)
  5. The sender party equals the session party that created the intent
  6. If the intent carries amount_expected, the on-chain amount matches exactly
  7. Each chain_tx_id / deposit_ref is credited at most once (idempotent)
FailureHandling
deposit_ref missing, expired, unknown or already usedNot credited; warn logged
Instrument mismatchNot credited; error logged
Sender party differs from the intentNot credited
Amount differs from amount_expectedNot credited; manual reconciliation
Wallet transfer succeeded but the bridge did not observe itKeep the update id; ops inspect the ledger update stream
Funds reached the exchange party but the Daml Credit failedOps retry the idempotent command or reconcile manually

If a user sends assets to the exchange party manually without a valid rocky:deposit: reference, the assets reach the custody party but the balance is not credited automatically. Contact support for manual reconciliation.


7. Development environments​

Local / dev environments can mint balance without a real transfer:

  • POST /v1/deposits/seed (requires DEV_TOOLS_ENABLED=true; off in production): canton-bridge creates a DepositIntent Daml contract signed by SHADOW_USER_PARTY_ID and credits it. The DepositIntent template is used only on this dev path; MainNet deposits never create it. See Seed Deposit
  • The spot session Dev Faucet