CBTC Quick Start
⚠️ API Disclaimer. CBTC APIs have no formal versioning policy today. All endpoints and library interfaces described in this guide are subject to change. Breaking changes are communicated via #cbtc-ecosystem and the changelog. This disclaimer will be updated once a formal versioning and stability policy is established.
This step-by-step guide walks you through minting your first CBTC (wrapped Bitcoin) on the Canton Network. You will authenticate with Keycloak, create a deposit account, send BTC to a Taproot address, and receive 1:1 backed CBTC on your Canton participant node. The full process takes about 15 minutes of active work plus ~60 minutes of Bitcoin confirmation time.
🎯 What you will accomplish
Authenticate to the Canton Network via Keycloak
Create a CBTC deposit account
Obtain a Bitcoin deposit address
Send BTC and wait for confirmation
Verify your CBTC balance
Send CBTC to another party (two-phase transfer)
Prerequisites for Minting CBTC
Before you begin minting wrapped Bitcoin on Canton, make sure you have the following:
Canton participant node
A running Canton participant node connected to the network. See Canton documentation for setup.
DA Registry Utility
Installed and configured. See Digital Asset Utilities docs.
Keycloak credentials
A valid Keycloak host, realm, client ID, username, and password for your environment.
Party ID
Your Canton Party ID, obtained during onboarding.
Rust toolchain
If using cbtc-lib (Rust). Install via rustup.rs.
BTC to deposit
Real BTC (mainnet) or testnet BTC (testnet). For testnet, you can use the CBTC Testnet Faucet to get test CBTC directly. For mainnet, you mint CBTC by depositing real BTC.
Choose Your CBTC Environment: Testnet or Mainnet
CBTC is available on three environments. Start with testnet for experimentation, then move to mainnet for production. CBTC also exists on Devnet, but minting and withdrawals are not available to external users on Devnet. You can use the faucet to obtain test CBTC for development.
🧪 Testnet vs. Mainnet: what is identical and what differs
Identical: DAR file, API surface, mint/burn flows, governance model, two-phase transfer mechanics
Differs: Attestor set (smaller on testnet), confirmation times (may be faster), Instrument IDs (different from mainnet), faucet-only BTC on testnet (no real value)
Mocked or unavailable on testnet: Real BTC settlement, production Attestor SLAs, mainnet fee structure
Operational note: Testnet may be reset without notice. Testnet CBTC balances and transaction history may not persist across resets. Do not rely on testnet state for production planning. Exact reset schedule and data persistence details to be confirmed with Engineering.
Environment Configuration
REGISTRY_URL
ATTESTOR_URL
DECENTRALIZED_PARTY_ID
Environment-specific. Provided during onboarding.
Environment-specific. Provided during onboarding.
Environment-specific. Provided during onboarding.
Set these as environment variables before running any commands:
Step 1: Authenticate with Keycloak
All CBTC operations require a valid Keycloak access token. The canton-lib crate provides a helper for this.
Using cbtc-lib (Rust)
Using the Keycloak API directly
Save the access_token from the response. You will pass it as a Bearer token in all subsequent API calls.
Step 2: Create a Deposit Account
A deposit account maps your Canton Party ID to a unique Bitcoin deposit address. You only need to create this once; the address can be reused for future deposits.
Using cbtc-lib
Using the Canton API directly
Submit a CreateDepositAccount command to the Canton Ledger API v2 endpoint. You can fetch the CBTCDepositAccountRules contract from an Attestor's /app/get-account-contract-rules endpoint.
Step 3: Get Your Bitcoin Deposit Address
Once the deposit account is created, retrieve the Bitcoin address associated with it. This address is derived from the Deposit Account's id field (or the contract_id if the Deposit Account is new).
Using cbtc-lib
Important: This address can be reused indefinitely for future deposits. You can also request additional deposit addresses if needed.
Step 4: Send BTC
Send Bitcoin to the deposit address using any standard Bitcoin wallet or tooling. There is no minimum deposit enforced at the protocol level, but check with BitSafe for any operational minimums.
After sending, you need to wait for 6 Bitcoin block confirmations before the Attestor network will process the deposit.
Step 5: Wait for Confirmations and Auto-Minting
Once your BTC transaction reaches 6 confirmations:
The Attestor network detects the confirmed deposit
Each Attestor independently verifies the transaction
When a threshold of Attestors confirm (via
ConfirmDepositActionon the CBTC Governance module), CBTC is automatically minted to your Canton PartyNo further action is required from you This process typically takes 60 to 90 minutes, depending on Bitcoin block times.
Step 6: Check Your CBTC Balance
Using cbtc-lib
Using the Canton API directly
Query active contracts filtered by the token holding interface:
💡 Filtering required. This query returns all token holdings, including Canton Coin (CC). To isolate your CBTC balance, you must filter the results client-side by the CBTC
instrumentId. Thecbtc-liblibrary handles this automatically viaactive_contracts::get. There is no single curl that can query and filter for CBTC holdings in one step. TheactiveAtOffsetmust be set to the actual latest offset from your ledger.
💡 UTXO model. CBTC uses a UTXO model similar to Bitcoin. Your balance may be spread across multiple holding contracts (soft limit of 10 UTXOs per party per token type). Use the
cbtc::consolidatemodule to merge UTXOs, orcbtc::splitto divide them.
Step 7: Transfer CBTC Between Canton Parties
CBTC transfers use a two-phase model: the sender creates an offer, and the receiver accepts it. This ensures both parties explicitly consent to the transfer.
Phase 1: Create a transfer offer (sender)
Phase 2: Accept the transfer (receiver)
ℹ️ No curl example for transfers. The raw API transfer flow requires 5-6 sequential API calls with contract disclosures and is too complex to represent as a single curl example. Use
cbtc-libfor transfers, or refer to the Canton Utility docs for the full API sequence.
Redeem CBTC: Convert Wrapped Bitcoin Back to BTC
To convert CBTC back to BTC:
Create a withdraw account specifying your Bitcoin destination address using the
cbtc::mint_redeem::redeemmoduleSubmit the withdrawal which burns CBTC on Canton
The Attestor network detects the burn and constructs a Bitcoin transaction
Attestors sign the transaction via threshold signing (FROST)
The BTC transaction is broadcast to the Bitcoin network
Using cbtc-lib
Using the Canton API directly
Submit a CBTCWithdrawAccount_Withdraw command. You can get the correct extraArgs and contract disclosures from an Attestor's /app/get-token-standard-contracts endpoint. The contractIds, templateIds, and blobs in this example are for illustration only:
Additional Operations
The cbtc-lib library provides several utility modules for managing your CBTC holdings:
cbtc::batch
Batch operations for sending CBTC from a CSV file
cbtc::distribute
Distribute CBTC across multiple parties
cbtc::consolidate
Merge multiple UTXO holdings into fewer contracts
cbtc::split
Split a single holding into multiple UTXOs
cbtc::active_contracts
Query your current CBTC holdings
Troubleshooting
My deposit has not been minted after 90 minutes
Verify the BTC transaction has at least 6 confirmations on a block explorer
Confirm you sent to the correct deposit address (from Step 3)
Check that your Canton participant node is connected and syncing
Escalation: contact [email protected] or post in #cbtc-ecosystem on Slack
Transfer offer is not appearing for the receiver
The receiver must be registered in the DA Registry with a valid credential
Confirm the receiver's Party ID is correct
Check that both parties are connected to the same Canton sync domain
"Insufficient holdings" error when sending
CBTC uses a UTXO model. You may need to consolidate holdings first using
cbtc::consolidateCheck your balance with
cbtc::active_contractsto verify available amounts
Authentication token expired
Keycloak tokens have a limited lifetime. Re-authenticate using Step 1 before retrying the operation
Next Steps
API Reference: Full documentation of Canton Ledger API endpoints for CBTC operations (coming soon)
SDK Reference: Complete
cbtc-libandcanton-libmodule documentation (coming soon)Authentication Guide: Detailed Keycloak setup and Auth0 community example (coming soon)
Integration Examples: Real-world code showing CBTC in DeFi protocols, wallets, and trading systems (coming soon)
📧 Need help? Reach out to [email protected] or post in #cbtc-ecosystem on Slack. For urgent technical issues, tag the engineering team directly in the Slack channel.
⚠️ Code updated per PR #22. All Rust code examples have been updated to match the actual
cbtcv0.3.0 andcanton-libv0.3.0 APIs (correct module paths, struct params, function signatures). Curl examples updated to use${LEDGER_HOST}without port. Final engineering sign-off by Jesse or Ferenc is still required before external publication.
Last updated