You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(bitcoin): improve CLI UX, fix heading structure, reorder Direct API sections (#170)
## Summary
### CLI copy-paste UX
The `### Interact with ckBTC using icp-cli` section previously had a
single monolithic code block with `YOUR-PRINCIPAL` literals that
required manual editing before every command. The section now:
- Exports `MY_PRINCIPAL` from the active identity in one setup block
(`icp identity get-principal`) so it never needs to be typed or edited.
- Splits each operation into its own copy-paste block with
`$MY_PRINCIPAL` interpolated via double-quote shell expansion.
- The transfer command includes `export
RECIPIENT="<paste-recipient-principal>"` at the top of the same block,
keeping it a single copy-paste operation while making the placeholder
explicit.
### Direct Bitcoin API section reordering
Previous order mixed monitoring utilities in with core read operations
and placed `### Blockchain info` immediately after `### Available
endpoints`, before the developer's first instinct (`get_balance`,
`get_utxos`). New order groups sections by purpose:
| Before | After |
|---|---|
| Bitcoin API canister IDs | Bitcoin API canister IDs |
| Available endpoints | Available endpoints |
| **Blockchain info** | **Read Bitcoin balance** |
| Read Bitcoin balance | **Read UTXOs** |
| Read UTXOs | **Get fee percentiles** |
| Get fee percentiles | **Blockchain info** |
| Developer workflow | Developer workflow |
| (UTXO selection as h4) | **UTXO selection (h3)** |
| Common mistakes | Common mistakes |
| Cycle costs | Cycle costs |
`Blockchain info` is a monitoring/diagnostics call — it belongs after
the core transaction-building reads, not before them.
### Developer workflow heading structure
`#### UTXO selection` was the only h4 in the entire file, sitting as a
lone child under `### Developer workflow`. This:
- Created a structurally awkward section (a heading with a single
subheading implies the parent section exists only to contain one thing).
- Buried the UTXO selection anchor below the fold of the workflow
section.
The fix promotes `#### UTXO selection` to `### UTXO selection` as a
sibling of `### Developer workflow`. The `### Developer workflow`
section now closes with the working-example links (which cover the full
flow, not just UTXO selection), and step 3 in the numbered list links
directly to `#utxo-selection` for readers who want to jump there.
### Em-dash cleanup
The previous PR (#169) introduced several em-dashes in new prose. All
instances outside code blocks are replaced with colons, semicolons, or
parentheses per the project's banned-terms rule.
## Sync recommendation
Informed by `dfinity/examples` — no source changes, documentation
improvements only.
All calls require cycles — see [Cycle costs](#cycle-costs). The `ic-cdk-bitcoin-canister` crate handles them automatically in Rust; in Motoko attach cycles explicitly with `(with cycles = amount)`.
463
-
464
-
### Blockchain info
465
-
466
-
`get_blockchain_info()` queries the state of the Bitcoin chain. The response includes:
467
-
468
-
| Field | Type | Description |
469
-
|---|---|---|
470
-
|`height`|`nat32`| Current chain tip block height |
471
-
|`block_hash`|`blob`| Chain tip block hash |
472
-
|`timestamp`|`nat32`| Unix timestamp of the tip block |
473
-
|`difficulty`|`nat`| Current mining difficulty target |
474
-
|`utxos_length`|`nat64`| Total number of UTXOs in the UTXO set |
475
-
476
-
<TabssyncKey="lang">
477
-
<TabItemlabel="Motoko">
478
-
479
-
```motoko
480
-
import Runtime "mo:core/Runtime";
481
-
import Text "mo:core/Text";
482
-
483
-
persistent actor Backend {
484
-
public type Network = { #mainnet; #testnet; #regtest };
Full implementation: [basic_bitcoin example (Rust)](https://github.com/dfinity/examples/tree/master/rust/basic_bitcoin) — `src/service/get_blockchain_info.rs`.
477
+
All calls require cycles (see [Cycle costs](#cycle-costs)). The `ic-cdk-bitcoin-canister` crate handles them automatically in Rust; in Motoko attach cycles explicitly with `(with cycles = amount)`.
`bitcoin_get_utxos` returns a `next_page` field. If non-null, the address has more UTXOs than fit in one response — call again with `filter = ?#page(next_page)` (Motoko) or `filter: Some(UtxosFilter::Page(next_page))` (Rust) until `next_page` is null.
671
+
`bitcoin_get_utxos` returns a `next_page` field. If non-null, the address has more UTXOs than fit in one response: call again with `filter = ?#page(next_page)` (Motoko) or `filter: Some(UtxosFilter::Page(next_page))` (Rust) until `next_page` is null.
767
672
768
673
### Get fee percentiles
769
674
770
-
Fee percentiles are measured in millisatoshi per vbyte (1,000 msat = 1 satoshi). The 50th percentile gives a reasonable median confirmation target. On regtest there are no transactions, so the response is empty — use a fallback.
675
+
Fee percentiles are measured in millisatoshi per vbyte (1,000 msat = 1 satoshi). The 50th percentile gives a reasonable median confirmation target. On regtest there are no transactions, so the response is empty: use a fallback.
Full implementation: [basic_bitcoin example (Rust)](https://github.com/dfinity/examples/tree/master/rust/basic_bitcoin), `src/service/get_blockchain_info.rs`.
870
+
856
871
### Developer workflow
857
872
858
873
Building a full Bitcoin transaction flow involves these steps:
859
874
860
875
1.**Generate a Bitcoin address** from a threshold ECDSA or Schnorr public key
861
876
2.**Read UTXOs** for the address using `bitcoin_get_utxos`
862
-
3.**Select UTXOs and calculate the fee**— see below
877
+
3.**Select UTXOs and calculate the fee**(see [UTXO selection](#utxo-selection)below)
863
878
4.**Build the unsigned transaction** from the selected UTXOs, recipient output, and change output
864
879
5.**Sign each input** using `sign_with_ecdsa` or `sign_with_schnorr`
865
880
6.**Submit the transaction** using `bitcoin_send_transaction`
866
881
867
-
#### UTXO selection
882
+
Address generation, transaction construction, signing, and submission together exceed 30 lines per language. See these working examples for the full flow:
883
+
884
+
-[basic_bitcoin (Motoko)](https://github.com/dfinity/examples/tree/master/motoko/basic_bitcoin): full send/receive with ECDSA and Schnorr
885
+
-[basic_bitcoin (Rust)](https://github.com/dfinity/examples/tree/master/rust/basic_bitcoin): full send/receive with ECDSA and Schnorr
Transaction fee depends on transaction size in bytes, which depends on the number of inputs, which depends on which UTXOs are selected. Because fee and input count are mutually dependent, the calculation is iterative: start with fee=0, select UTXOs to cover `amount + 0`, estimate the signed transaction size with a mock signer, recalculate fee, repeat until the fee stabilises.
870
891
871
892
Two selection strategies cover the common cases:
872
893
873
894
**Greedy (standard payments):** accumulate UTXOs oldest-first until the total covers `amount + fee`. Consolidates old UTXOs and reduces wallet fragmentation over time.
874
895
875
-
**Single UTXO (Ordinals, Runes, BRC-20):** find the first UTXO that alone covers `amount + fee`. Required when the asset is inscribed on a specific satoshi — spending multiple UTXOs risks accidentally burning the inscription.
896
+
**Single UTXO (Ordinals, Runes, BRC-20):** find the first UTXO that alone covers `amount + fee`. Required when the asset is inscribed on a specific satoshi; spending multiple UTXOs risks accidentally burning the inscription.
876
897
877
898
<TabssyncKey="lang">
878
899
<TabItemlabel="Motoko">
@@ -954,12 +975,6 @@ fn select_one_utxo<'a>(
954
975
</TabItem>
955
976
</Tabs>
956
977
957
-
Address generation, transaction construction, signing, and submission together exceed 30 lines per language. See these working examples for the full flow:
958
-
959
-
-[basic_bitcoin (Motoko)](https://github.com/dfinity/examples/tree/master/motoko/basic_bitcoin): full send/receive with ECDSA and Schnorr
960
-
-[basic_bitcoin (Rust)](https://github.com/dfinity/examples/tree/master/rust/basic_bitcoin): full send/receive with ECDSA and Schnorr
-**Not paginating `bitcoin_get_utxos`.** The response includes a `next_page` field. For addresses with many transactions a single call may not return all UTXOs. If `next_page` is non-null, call again with `filter = ?#page(next_page)` (Motoko) or `UtxosFilter::Page(next_page)` (Rust) until `next_page` is null.
0 commit comments