Skip to content

Commit

Permalink
feat: add tabs for swift and kotlin to the starter (quickstart) example
Browse files Browse the repository at this point in the history
  • Loading branch information
riverKanies committed Oct 21, 2024
1 parent 0a37f84 commit 82624dd
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 32 deletions.
157 changes: 129 additions & 28 deletions docs/cookbook/starter.md
Original file line number Diff line number Diff line change
@@ -1,63 +1,164 @@
# Quick Start Example

This page details the code in the <a href="https://github.com/bitcoindevkit/book-of-bdk/tree/master/examples/rust/quickstart" target="_blank">quickstart</a> example in the `examples` folder of the _Book of BDK_.
This page details the code in the quickstart example in the `examples` folder of the _Book of BDK_. You can view and run the code for the example in your preferred language:

=== "Rust"

<a href="https://github.com/bitcoindevkit/book-of-bdk/tree/master/examples/rust/quickstart" target="_blank">Rust quickstart example -></a>

=== "Swift"

<a href="https://github.com/bitcoindevkit/book-of-bdk/tree/master/examples/swift/quickstart" target="_blank">Swift quickstart example -></a>

=== "Kotlin"

<a href="https://github.com/bitcoindevkit/book-of-bdk/tree/master/examples/kotlin/quickstart" target="_blank">Kotlin quickstart example -></a>

!!! tip
This page is up-to-date with version `1.0.0-beta.5` of `bdk_wallet`.

## Create a new Rust project
## Create a new project

=== "Rust"

```shell
cargo init fullwallet
cd fullwallet
```

=== "Swift"

Create a new Swift project in Xcode.

=== "Kotlin"

```shell
cargo init fullwallet
cd fullwallet
```
Create a new Kotlin project in your preferred IDE.

## Add required dependencies to your `Cargo.toml` file
## Add required dependencies

```toml
--8<-- "examples/rust/quickstart/Cargo.toml"
```
=== "Rust"

## Create a wallet, sync it and display the balance in `src/main.rs`
```toml title="Cargo.toml"
--8<-- "examples/rust/quickstart/Cargo.toml"
```

=== "Swift"

1. From the Xcode File menu, select Add Package Dependencies...
2. Enter `https://github.com/bitcoindevkit/bdk-swift` into the package repository URL text field

=== "Kotlin"

```kotlin title="build.gradle"
--8<-- "examples/kotlin/quickstart/build.gradle"
```

## Create a wallet, sync it and display the balance

We'll give a breakdown of the key pieces of this code in the next section.
```rust title="examples/rust/quickstart/src/main.rs""
--8<-- "examples/rust/quickstart/src/main.rs:file"
```
=== "Rust"

```rust title="examples/rust/quickstart/src/main.rs""
--8<-- "examples/rust/quickstart/src/main.rs:file"
```

=== "Swift"

```swift title="examples/swift/quickstart/main.swift"
--8<-- "examples/swift/quickstart/main.swift:file"
```

=== "Kotlin"

```kotlin title="examples/kotlin/quickstart/main.kt"
--8<-- "examples/kotlin/quickstart/main.kt:file"
```

## Build and run:

The wallet will take a few seconds to sync, then you should see the wallet balance printed in the terminal.
```shell
cargo build
cargo run
```
=== "Rust"

## Let's take a closer look at what's going on in `src/main.rs`:
```shell
cargo build
cargo run
```

=== "Swift"

Run the project in Xcode.

=== "Kotlin"

Run the project in your IDE.

## Let's take a closer look:

## Descriptors

First we need some <a href="https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md" target="_blank">descriptors</a> to instantiate our wallet. In this example we will use public key descriptors to simply display the balance of a wallet. To actually sign transactions you will need to use a wallet that is instantiated with private key descriptors. Refer to the [Working with Descriptors](./keys-descriptors/descriptors.md) page for information on how to generate your own private key descriptors.
```rust
--8<-- "examples/rust/quickstart/src/main.rs:descriptors"
```
=== "Rust"

```rust
--8<-- "examples/rust/quickstart/src/main.rs:descriptors"
```

=== "Swift"

```swift
--8<-- "examples/swift/quickstart/main.swift:descriptors"
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/quickstart/main.kt:descriptors"
```
These are taproot `tr()` descriptors using a public key on testnet (or signet) `tpub` as described in <a href="https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki" target="_blank">BIP86</a>. The `EXTERNAL_DESCRIPTOR` is an HD wallet with a path for generating addresses to give out externally for payment. We also have a second `INTERNAL_DESCRIPTOR` that we can use to generate addresses to pay ourseves change when sending payments (remeber that <a href="https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch06_transactions.adoc#outpoint" target="_blank">UTXOs</a> must be spent if full, so you often want to make change).

## Blockchain Client and Network

This example is using an <a href="https://github.com/Blockstream/esplora" target="_blank">Esplora</a> client on <a href="https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch11_blockchain.adoc#signet-the-proof-of-authority-testnet" target="_blank">Signet</a> hosted by the BDK team.
```rust
--8<-- "examples/rust/quickstart/src/main.rs:client"
```
=== "Rust"

```rust
--8<-- "examples/rust/quickstart/src/main.rs:client"
```

=== "Swift"

```swift
--8<-- "examples/swift/quickstart/main.swift:client"
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/quickstart/main.kt:client"
```
Other options for blockchain clients include running an Electrum light wallet or using RPC on a bitcoind fullnode. We are using Esplora in this example as it is the most powerfull of these three options.
This example also used the Signet network, which is a test network that has some control mechanisms that ensure the network state is pretty similar to the blockchain mainnet (Testnet doesn't have those guarantees). You may alternatively want to run this example wallet using a locally hosted Regtest network, however the details of how to set that up are beyond the scope of this example.

## Scan

Once we have our wallet setup and connected to the network, we scan the network to detect UTXOs relevant to our wallet.
```rust
--8<-- "examples/rust/quickstart/src/main.rs:scan"
```
=== "Rust"

```rust
--8<-- "examples/rust/quickstart/src/main.rs:scan"
```

=== "Swift"

```swift
--8<-- "examples/swift/quickstart/main.swift:scan"
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/quickstart/main.kt:scan"
```
This scanning process is detailed in [Full Scan vs Sync](./syncing/full-scan-vs-sync.md). The scanning process checks child pubkeys for the descriptors specified in the wallet to detect UTXOs that can be spent by the wallet. That scan data is then applied to the wallet.

### Display Wallet Balance
Expand Down
10 changes: 10 additions & 0 deletions examples/kotlin/quickstart/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
repositories {
mavenCentral()
}

dependencies {
// for jvm
implementation 'org.bitcoindevkit:bdk-jvm:<version>'
// OR for android
implementation 'org.bitcoindevkit:bdk-android:<version>'
}
34 changes: 34 additions & 0 deletions examples/kotlin/quickstart/main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// --8<-- [start:file]

// --8<-- [start:descriptors]
val descriptor = "tr([12071a7c/86'/1'/0']tpubDCaLkqfh67Qr7ZuRrUNrCYQ54sMjHfsJ4yQSGb3aBr1yqt3yXpamRBUwnGSnyNnxQYu7rqeBiPfw3mjBcFNX4ky2vhjj9bDrGstkfUbLB9T/0/*)#z3x5097m"
val changeDescriptor = "tr([12071a7c/86'/1'/0']tpubDCaLkqfh67Qr7ZuRrUNrCYQ54sMjHfsJ4yQSGb3aBr1yqt3yXpamRBUwnGSnyNnxQYu7rqeBiPfw3mjBcFNX4ky2vhjj9bDrGstkfUbLB9T/1/*)#n9r4jswr"
// --8<-- [end:descriptors]

val wallet = Wallet(
descriptor,
changeDescriptor,
Network.SIGNET
)

// --8<-- [start:address]
val addressInfo = wallet.revealNextAddress(KeychainKind.EXTERNAL)
println("Generated address ${addressInfo.address} at index ${addressInfo.index}")
// --8<-- [end:address]

// --8<-- [start:client]
val esploraClient: EsploraClient = EsploraClient("https://mutinynet.com/api")
// --8<-- [end:client]

// --8<-- [start:scan]
val syncRequest = wallet.startSyncWithRevealedSpks()
val update = try esploraClient.sync(
syncRequest,
5uL
)
wallet.applyUpdate(update)
val balance = wallet.balance()
println("Wallet balance: ${balance.total()} sat")
// --8<-- [end:scan]

// --8<-- [end:file]
7 changes: 3 additions & 4 deletions examples/rust/quickstart/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use bdk_wallet::chain::spk_client::{FullScanRequestBuilder, FullScanResult};

const STOP_GAP: usize = 50;
const PARALLEL_REQUESTS: usize = 1;

// --8<-- [start:descriptors]
const EXTERNAL_DESCRIPTOR: &str = "tr([12071a7c/86'/1'/0']tpubDCaLkqfh67Qr7ZuRrUNrCYQ54sMjHfsJ4yQSGb3aBr1yqt3yXpamRBUwnGSnyNnxQYu7rqeBiPfw3mjBcFNX4ky2vhjj9bDrGstkfUbLB9T/0/*)#z3x5097m";
const INTERNAL_DESCRIPTOR: &str = "tr([12071a7c/86'/1'/0']tpubDCaLkqfh67Qr7ZuRrUNrCYQ54sMjHfsJ4yQSGb3aBr1yqt3yXpamRBUwnGSnyNnxQYu7rqeBiPfw3mjBcFNX4ky2vhjj9bDrGstkfUbLB9T/1/*)#n9r4jswr";
Expand All @@ -32,16 +33,14 @@ fn main() -> () {
// --8<-- [start:client]
let client: esplora_client::BlockingClient = Builder::new("http://signet.bitcoindevkit.net").build_blocking();
// --8<-- [end:client]

// --8<-- [start:scan]
let full_scan_request: FullScanRequestBuilder<KeychainKind> = wallet.start_full_scan();
let update: FullScanResult<KeychainKind> = client.full_scan(full_scan_request, STOP_GAP, PARALLEL_REQUESTS).unwrap();

// Apply the update from the full scan to the wallet
wallet.apply_update(update).unwrap();
// --8<-- [end:scan]

// Query the wallet balance again
let balance = wallet.balance();
println!("Wallet balance: {} sat", balance.total().to_sat());
// --8<-- [end:scan]
}
// --8<-- [end:file]
34 changes: 34 additions & 0 deletions examples/swift/quickstart/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// --8<-- [start:file]

// --8<-- [start:descriptors]
let descriptor = "tr([12071a7c/86'/1'/0']tpubDCaLkqfh67Qr7ZuRrUNrCYQ54sMjHfsJ4yQSGb3aBr1yqt3yXpamRBUwnGSnyNnxQYu7rqeBiPfw3mjBcFNX4ky2vhjj9bDrGstkfUbLB9T/0/*)#z3x5097m"
let changeDescriptor = "tr([12071a7c/86'/1'/0']tpubDCaLkqfh67Qr7ZuRrUNrCYQ54sMjHfsJ4yQSGb3aBr1yqt3yXpamRBUwnGSnyNnxQYu7rqeBiPfw3mjBcFNX4ky2vhjj9bDrGstkfUbLB9T/1/*)#n9r4jswr"
// --8<-- [end:descriptors]

let wallet = try Wallet(
descriptor: descriptor,
changeDescriptor: changeDescriptor,
network: Network.signet
)

// --8<-- [start:address]
let addressInfo = wallet.revealNextAddress(keychain: .external)
print("Generated address \(addressInfo.address) at index \(addressInfo.index)")
// --8<-- [end:address]

// --8<-- [start:client]
let esploraClient = EsploraClient(url: "https://mutinynet.com/api")
// --8<-- [end:client]

// --8<-- [start:scan]
let syncRequest = wallet.startSyncWithRevealedSpks()
let update = try esploraClient.sync(
syncRequest: syncRequest,
parallelRequests: UInt64(5)
)
try wallet.applyUpdate(update: update)
let balance = wallet.balance()
print("Wallet balance: \(balance.total) sat")
// --8<-- [end:scan]

// --8<-- [end:file]

0 comments on commit 82624dd

Please sign in to comment.