BTC Pool Canister
Bitcoin liquidity custody with boosted withdrawals and UTXO management
Responsibilities
- Accept ckBTC deposits from users
- Process withdrawals (converting ckBTC → BTC)
- Handle borrow requests from the lending canister
- Optimize fees via withdrawal batching for small amounts
- Manage UTXOs for the pool's Bitcoin address
Architecture
Subaccount Architecture
The pool uses deterministic subaccount derivation for user isolation:
Subaccount Types
| Type | Prefix | Purpose |
|---|---|---|
| Inflow Deposit | 0x1 | User deposits |
| Inflow Repay | 0x2 | Debt repayments |
| Mapped Outflow | 0x3 | Direct address withdrawals |
| Native Outflow | 0x5 | IC Principal transfers |
| Boost | Internal | Small withdrawal batching |
Inflow Subaccounts
For deposits and repayments, subaccounts are derived from the user's principal:
[prefix, 0x0, length, ...principal_bytes..., ...padding]
byte 0 byte 1 byte 2 bytes 3-N bytes N-31Example - Deposit subaccount:
[0x1, 0x0, 0x0A, <10 principal bytes>, <19 zero bytes>]Outflow Subaccounts (Mapped)
Bitcoin addresses can be long, so they're mapped to a u128 index:
[0x3, <15 zero bytes>, <16 bytes of u128 index>]The pool maintains bidirectional mappings:
ADDRESS_OUTFLOW_SUBACCOUNT: address → indexADDRESS_OUTFLOW_SUBACCOUNT_REVERSE: index → address
Special Subaccounts
BOOST_SUBACCOUNT:
[0x0, 0x1, <30 zero bytes>]Holds ckBTC for boosted withdrawals awaiting batching.
Two-Tier Withdrawal System
Standard Withdrawals (>50,000 sats)
Direct ckBTC burn via the minter:
Boosted Withdrawals (Under 50,000 sats)
Problem: Bitcoin transaction fees make small withdrawals uneconomical.
Solution: Batch multiple small withdrawals into a single Bitcoin transaction.
Boosted Withdrawal Flow:
- Pool transfers ckBTC to
BOOST_SUBACCOUNT - Withdrawal added to pending queue
- Every 5 minutes, pending withdrawals are processed (even if there's only one)
- Pool creates multi-output Bitcoin transaction (or single output if only one withdrawal)
- Transaction signed using threshold ECDSA
- Transaction broadcast to Bitcoin network
- Pool fronts BTC immediately from its UTXOs
- When boost balance exceeds 50k sats, accumulated ckBTC is burned
Benefits:
- Users receive BTC faster
- Lower effective fees (shared across batch)
- Pool recoups fronted BTC via ckBTC burn
Inflow Detection
The pool scans for new deposits and repayments every 60 seconds:
Treasury Movement Detection
After inflows are transferred to treasury, the pool detects and creates events:
Background Tasks
| Task | Interval | Purpose |
|---|---|---|
check_for_new_subaccount_inflows | 60s | Scan for new deposits/repayments |
process_treasury_movements | 60s | Detect confirmed deposits, create events |
process_event_queue | 60s | Send notifications to lending canister |
process_boosted_withdrawals | 300s | Batch small withdrawals |
check_boosted_withdrawals_status | 60s | Monitor on-chain confirmations |
burn_accumulated_boost_ckbtc | 60s | Recoup fronted BTC |
frozen_utxos_cleanup | 12h | Remove stale UTXO locks |
UTXO Management
The pool manages UTXOs for its Bitcoin address:
UTXO Freezing
When UTXOs are used in a transaction, they're temporarily frozen to prevent double-spending:
// After broadcasting transaction
for input in used_inputs {
FROZEN_UTXOS.insert(input.to_string(), timestamp);
}UTXO Selection
For boosted withdrawals, UTXOs are selected largest-first:
let mut utxos = get_available_utxos();
utxos.sort_by(|a, b| b.value.cmp(&a.value)); // largest first
let (selected, fee, total) = fund_transaction(&mut tx, utxos, fee_rate);Cleanup
Frozen UTXOs are released after 12 hours if their transaction hasn't confirmed:
fn frozen_utxos_cleanup() {
let cutoff = now() - 12 * 3600;
for (utxo, freeze_time) in FROZEN_UTXOS {
if freeze_time < cutoff {
FROZEN_UTXOS.remove(&utxo);
}
}
}Threshold ECDSA Signing
Bitcoin transactions are signed using ICP's threshold ECDSA:
let signature = sign_with_ecdsa(SignWithEcdsaArgument {
message_hash: sighash_data,
derivation_path: vec![],
key_id: EcdsaKeyId {
curve: EcdsaCurve::Secp256k1,
name: KEY_NAME.to_string(),
},
}).await;This provides:
- Decentralized key management
- No single point of failure
- Cryptographic security guarantees